Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
v1.2.0 (#17)
Browse files Browse the repository at this point in the history
* Add plugin settings page + Move some params to settings page + Adjust existing actions to next changes + Move shared functions to internal/private header #10 #11 #12

* Add comments and adjust some shared functions to avoid repetitions

* Adjustments to enable multiple bindings mode

* Fix typo

* Adjust settings section

* Reset weak ptr

* Add an option to allow overriding default binding owner + Fix input bindings on pawn

* Add a separate file to define logs + Remove unnecessary includes + Fix packaging

* Add empty FilterPlugin.ini

* Set work in progress feature as private

* Add missing include

* Update settings

* Remove unnecessary warning

* Adjust settings name + Add const to spec params

* Initialize boolean property and adjust include
  • Loading branch information
lucoiso authored Nov 12, 2022
1 parent 38e98ce commit 07f3b2f
Show file tree
Hide file tree
Showing 20 changed files with 572 additions and 231 deletions.
1 change: 1 addition & 0 deletions Config/FilterPlugin.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[FilterPlugin]
Binary file modified ModularFeatures_ExtraActions.uplugin
Binary file not shown.
3 changes: 2 additions & 1 deletion Source/ModularFeatures_ExtraActions.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public ModularFeatures_ExtraActions(ReadOnlyTargetRules Target) : base(Target)
"GameplayAbilities",
"GameplayTags",
"GameFeatures",
"ModularGameplay"
"ModularGameplay",
"DeveloperSettings"
});
}
}
2 changes: 1 addition & 1 deletion Source/Private/AbilityInputBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
// Year: 2022
// Repo: https://github.com/lucoiso/UEModularFeatures_ExtraActions

#include "AbilityInputBinding.h"
#include "AbilityInputBinding.h"
102 changes: 56 additions & 46 deletions Source/Private/GameFeatureAction_AddAbilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
// Repo: https://github.com/lucoiso/UEModularFeatures_ExtraActions

#include "GameFeatureAction_AddAbilities.h"
#include "AbilityInputBinding.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "Components/GameFrameworkComponentManager.h"
#include "Engine/AssetManager.h"
#include "InputAction.h"
#include "ModularFeatures_InternalFuncs.h"

Expand Down Expand Up @@ -63,11 +59,17 @@ void UGameFeatureAction_AddAbilities::HandleActorExtension(AActor* Owner, const

else if (EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded || EventName == UGameFrameworkComponentManager::NAME_GameActorReady)
{
if (ActiveExtensions.Contains(Owner) || !ActorHasAllRequiredTags(Owner, RequireTags))
// We don't want to repeat the addition and cannot add if the user don't have the required tags
if (ActiveExtensions.Contains(Owner) || !ModularFeaturesHelper::ActorHasAllRequiredTags(Owner, RequireTags))
{
return;
}

InputIDEnumeration_Ptr.Reset();

// Load the enumeration and save it before the loop to avoid high disk consumption due to loading a soft reference a lot of times since there's only 1 enumeration
InputIDEnumeration_Ptr = ModularFeaturesHelper::LoadInputEnum();

for (const FAbilityMapping& Entry : Abilities)
{
if (Entry.AbilityClass.IsNull())
Expand All @@ -79,48 +81,57 @@ void UGameFeatureAction_AddAbilities::HandleActorExtension(AActor* Owner, const
AddActorAbilities(Owner, Entry);
}
}

// Free the pointer. We only need this enum when we're adding abilities
InputIDEnumeration_Ptr.Reset();
}
}

void UGameFeatureAction_AddAbilities::AddActorAbilities(AActor* TargetActor, const FAbilityMapping& Ability)
{
// Only proceed if the target actor is valid and has authority
if (!IsValid(TargetActor) || TargetActor->GetLocalRole() != ROLE_Authority)
{
return;
}

if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
// If InputID Enumeration using is disabled, assume -1 as value
const int32 InputID = ModularFeaturesHelper::GetInputIDByName(Ability.InputIDValueName, InputIDEnumeration_Ptr.Get());

//Check if there's a existing ability data already loaded
FActiveAbilityData& NewAbilityData = ActiveExtensions.FindOrAdd(TargetActor);

const uint32 InputID = InputIDEnumerationClass.LoadSynchronous()->GetValueByName(Ability.InputIDValueName, EGetByNameFlags::CheckAuthoredName);

// Load the ability class and store into a const variable
const TSubclassOf<UGameplayAbility> AbilityToAdd = Ability.AbilityClass.LoadSynchronous();

UE_LOG(LogGameplayFeaturesExtraActions, Display, TEXT("%s: Adding ability %s to Actor %s."), *FString(__func__), *AbilityToAdd->GetName(), *TargetActor->GetName());

// Create the spec, used to give the ability to target's ability system component
FGameplayAbilitySpec NewAbilitySpec(AbilityToAdd, Ability.AbilityLevel, InputID, TargetActor);

const FGameplayAbilitySpec NewAbilitySpec(AbilityToAdd, Ability.AbilityLevel, InputID, TargetActor);

// Try to give the ability to the target and check if the spec handle is valid
if (const FGameplayAbilitySpecHandle NewSpecHandle = AbilitySystemComponent->GiveAbility(NewAbilitySpec);
NewSpecHandle.IsValid())
{
// Add the spec handle to the ability data
NewAbilityData.SpecHandle.Add(NewSpecHandle);


// Only bind the input if the Input Action is valid. This is not mandatory due to passive abilities that don't need to be associated to inputs
if (!Ability.InputAction.IsNull())
{
if (const IAbilityInputBinding* const SetupInputInterface = ModularFeaturesHelper::GetAbilityInputBindingInterface(TargetActor, InputBindingOwner))
{
UInputAction* const AbilityInput = Ability.InputAction.LoadSynchronous();
IAbilityInputBinding::Execute_SetupAbilityInputBinding(SetupInputInterface->_getUObject(), AbilityInput, InputID);
// Get the target Ability Input Binding interface
const IAbilityInputBinding* const SetupInputInterface = ModularFeaturesHelper::GetAbilityInputBindingInterface(TargetActor, InputBindingOwnerOverride);

NewAbilityData.InputReference.Add(AbilityInput);
}
else
// If we can bind the input to the target interface, we must add the input reference to the ability data
if (UInputAction* const AbilityInput = Ability.InputAction.LoadSynchronous();
ModularFeaturesHelper::BindAbilityInputToInterfaceOwner(SetupInputInterface, AbilityInput, NewAbilitySpec))
{
UE_LOG(LogGameplayFeaturesExtraActions, Error, TEXT("%s: Failed to setup input binding for ability %s on Actor %s."), *FString(__func__), *AbilityToAdd->GetName(), *TargetActor->GetName());
NewAbilityData.InputReference.Add(AbilityInput);
}
}

ActiveExtensions.Add(TargetActor, NewAbilityData);
}
}
Expand All @@ -132,54 +143,53 @@ void UGameFeatureAction_AddAbilities::AddActorAbilities(AActor* TargetActor, con

void UGameFeatureAction_AddAbilities::RemoveActorAbilities(AActor* TargetActor)
{
// Only proceed if the target actor is valid
if (!IsValid(TargetActor))
{
ActiveExtensions.Remove(TargetActor);
return;
}

// Only proceed if the target actor has authority
if (TargetActor->GetLocalRole() != ROLE_Authority)
{
return;
}

const FActiveAbilityData ActiveAbilities = ActiveExtensions.FindRef(TargetActor);

// Check if we can remove the abilities from this target actor by checking if it is inside the active extensions map
FActiveAbilityData ActiveAbilities = ActiveExtensions.FindRef(TargetActor);
if constexpr (&ActiveAbilities == nullptr)
{
UE_LOG(LogGameplayFeaturesExtraActions, Warning, TEXT("%s: No active abilities found for Actor %s."), *FString(__func__), *TargetActor->GetName());
ActiveExtensions.Remove(TargetActor);
return;
}
else

if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
UE_LOG(LogGameplayFeaturesExtraActions, Display, TEXT("%s: Removing associated abilities from Actor %s."), *FString(__func__), *TargetActor->GetName());
UE_LOG(LogGameplayFeaturesExtraActions, Display, TEXT("%s: Removing associated abilities from Actor %s."), *FString(__func__), *TargetActor->GetName());

for (const FGameplayAbilitySpecHandle& SpecHandle : ActiveAbilities.SpecHandle)
// Iterate the active abilities and remove all spec handle associated to this actor
for (const FGameplayAbilitySpecHandle& SpecHandle : ActiveAbilities.SpecHandle)
{
if (SpecHandle.IsValid())
{
if (SpecHandle.IsValid())
{
AbilitySystemComponent->SetRemoveAbilityOnEnd(SpecHandle);
AbilitySystemComponent->ClearAbility(SpecHandle);
}
}

if (const IAbilityInputBinding* const SetupInputInterface = ModularFeaturesHelper::GetAbilityInputBindingInterface(TargetActor, InputBindingOwner))
{
for (const UInputAction* const& InputRef : ActiveAbilities.InputReference)
{
if (IsValid(InputRef))
{
IAbilityInputBinding::Execute_RemoveAbilityInputBinding(SetupInputInterface->_getUObject(), InputRef);
}
}
// Set the ability to be removed on end and clear it
AbilitySystemComponent->SetRemoveAbilityOnEnd(SpecHandle);
AbilitySystemComponent->ClearAbility(SpecHandle);
}
}
else if (IsValid(GetWorld()) && IsValid(GetWorld()->GetGameInstance()))

// Get the interface owner and try to remove the input bindings
if (const IAbilityInputBinding* const SetupInputInterface = ModularFeaturesHelper::GetAbilityInputBindingInterface(TargetActor, InputBindingOwnerOverride))
{
UE_LOG(LogGameplayFeaturesExtraActions, Error, TEXT("%s: Failed to find AbilitySystemComponent on Actor %s."), *FString(__func__), *TargetActor->GetName());
ModularFeaturesHelper::RemoveAbilityInputInInterfaceOwner(SetupInputInterface->_getUObject(), ActiveAbilities.InputReference);
}
}
else if (IsValid(GetWorld()) && IsValid(GetWorld()->GetGameInstance()))
{
UE_LOG(LogGameplayFeaturesExtraActions, Error, TEXT("%s: Failed to find AbilitySystemComponent on Actor %s."), *FString(__func__), *TargetActor->GetName());
}

ActiveExtensions.Remove(TargetActor);
}
}
20 changes: 16 additions & 4 deletions Source/Private/GameFeatureAction_AddAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// Repo: https://github.com/lucoiso/UEModularFeatures_ExtraActions

#include "GameFeatureAction_AddAttribute.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "Components/GameFrameworkComponentManager.h"
#include "ModularFeatures_InternalFuncs.h"
#include "Runtime/Launch/Resources/Version.h"
Expand Down Expand Up @@ -61,7 +59,8 @@ void UGameFeatureAction_AddAttribute::HandleActorExtension(AActor* Owner, const

else if (EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded || EventName == UGameFrameworkComponentManager::NAME_GameActorReady)
{
if (ActiveExtensions.Contains(Owner) || !ActorHasAllRequiredTags(Owner, RequireTags))
// We don't want to repeat the addition and cannot add if the user don't have the required tags
if (ActiveExtensions.Contains(Owner) || !ModularFeaturesHelper::ActorHasAllRequiredTags(Owner, RequireTags))
{
return;
}
Expand All @@ -79,23 +78,31 @@ void UGameFeatureAction_AddAttribute::HandleActorExtension(AActor* Owner, const

void UGameFeatureAction_AddAttribute::AddAttribute(AActor* TargetActor)
{
// Only proceed if the target actor is valid and has authority
if (!IsValid(TargetActor) || TargetActor->GetLocalRole() != ROLE_Authority)
{
return;
}

// Get the ability system component of the target actor
if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
// Load and store the AttributeSet Class into a const variable
if (const TSubclassOf<UAttributeSet> SetType = Attribute.LoadSynchronous())
{
// Create the AttributeSet object
UAttributeSet* const NewSet = NewObject<UAttributeSet>(AbilitySystemComponent->GetOwnerActor(), SetType);

// Check if the user wants to initialize the AttributeSet with a DataTable. If true, will load and initialize the AttributeSet using the metadatas from it
if (!InitializationData.IsNull())
{
NewSet->InitFromMetaDataTable(InitializationData.LoadSynchronous());
}

// Add the attribute set to the ability system component
AbilitySystemComponent->AddAttributeSetSubobject(NewSet);

// Force the ability system component to replicate the attribute addition
AbilitySystemComponent->ForceReplication();

UE_LOG(LogGameplayFeaturesExtraActions, Display, TEXT("%s: Attribute %s added to Actor %s."), *FString(__func__), *SetType->GetName(), *TargetActor->GetName());
Expand All @@ -115,19 +122,23 @@ void UGameFeatureAction_AddAttribute::AddAttribute(AActor* TargetActor)

void UGameFeatureAction_AddAttribute::RemoveAttribute(AActor* TargetActor)
{
// Only proceed if the target actor is valid
if (!IsValid(TargetActor))
{
ActiveExtensions.Remove(TargetActor);
return;
}


// Only proceed if the target actor has authority
if (TargetActor->GetLocalRole() != ROLE_Authority)
{
return;
}

// Get the ability system component of the target actor
if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
// Get the added Attribute Set to the target actor by searching inside the Active Extensions, remove it from the Ability System Component and force a replication
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1
if (UAttributeSet* const AttributeToRemove = ActiveExtensions.FindRef(TargetActor).Get())
{
Expand All @@ -145,6 +156,7 @@ void UGameFeatureAction_AddAttribute::RemoveAttribute(AActor* TargetActor)
}
#endif
}
// We don't need to warn the user if there's no valid world or game instance, since this is a common case when the game is shutting down
else if (IsValid(GetWorld()) && IsValid(GetWorld()->GetGameInstance()))
{
UE_LOG(LogGameplayFeaturesExtraActions, Error, TEXT("%s: Failed to find AbilitySystemComponent on Actor %s."), *FString(__func__), *TargetActor->GetName());
Expand Down
18 changes: 15 additions & 3 deletions Source/Private/GameFeatureAction_AddEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// Repo: https://github.com/lucoiso/UEModularFeatures_ExtraActions

#include "GameFeatureAction_AddEffects.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "Components/GameFrameworkComponentManager.h"
#include "ModularFeatures_InternalFuncs.h"

Expand Down Expand Up @@ -60,7 +58,8 @@ void UGameFeatureAction_AddEffects::HandleActorExtension(AActor* Owner, const FN

else if (EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded || EventName == UGameFrameworkComponentManager::NAME_GameActorReady)
{
if (ActiveExtensions.Contains(Owner) || !ActorHasAllRequiredTags(Owner, RequireTags))
// We don't want to repeat the addition and cannot add if the user don't have the required tags
if (ActiveExtensions.Contains(Owner) || !ModularFeaturesHelper::ActorHasAllRequiredTags(Owner, RequireTags))
{
return;
}
Expand All @@ -81,28 +80,36 @@ void UGameFeatureAction_AddEffects::HandleActorExtension(AActor* Owner, const FN

void UGameFeatureAction_AddEffects::AddEffects(AActor* TargetActor, const FEffectStackedData& Effect)
{
// Only proceed if the target actor is valid and has authority
if (!IsValid(TargetActor) || TargetActor->GetLocalRole() != ROLE_Authority)
{
return;
}

// Get the ability system component of the target actor
if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
// Check if there's already added spec data applied to the target actor
TArray<FActiveGameplayEffectHandle>& SpecData = ActiveExtensions.FindOrAdd(TargetActor);

// Load the Effect class into a const variable
const TSubclassOf<UGameplayEffect> EffectClass = Effect.EffectClass.LoadSynchronous();

UE_LOG(LogGameplayFeaturesExtraActions, Display, TEXT("%s: Adding effect %s level %u to Actor %s with %u SetByCaller params."), *FString(__func__), *EffectClass->GetName(), Effect.EffectLevel, *TargetActor->GetName(), Effect.SetByCallerParams.Num());

// Create the outgoing spec handle to define the SetByCaller settings and apply the data to the target Ability System Component
const FGameplayEffectSpecHandle SpecHandle = AbilitySystemComponent->MakeOutgoingSpec(EffectClass, Effect.EffectLevel, AbilitySystemComponent->MakeEffectContext());

// Iterate the Set By Caller params and add the data to the Spec Handle Data
for (const TPair<FGameplayTag, float>& SetByCallerParam : Effect.SetByCallerParams)
{
SpecHandle.Data.Get()->SetSetByCallerMagnitude(SetByCallerParam.Key, SetByCallerParam.Value);
}

// Apply the effect data to the target Ability System Component
const FActiveGameplayEffectHandle NewActiveEffect = AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get());

// Add the active effect handle to the Spec Data before adding it to the ActiveExtensions map
SpecData.Add(NewActiveEffect);

ActiveExtensions.Add(TargetActor, SpecData);
Expand All @@ -115,24 +122,29 @@ void UGameFeatureAction_AddEffects::AddEffects(AActor* TargetActor, const FEffec

void UGameFeatureAction_AddEffects::RemoveEffects(AActor* TargetActor)
{
// Only proceed if the target actor is valid
if (!IsValid(TargetActor))
{
ActiveExtensions.Remove(TargetActor);
return;
}

// Only proceed if the target actor has authority
if (TargetActor->GetLocalRole() != ROLE_Authority)
{
return;
}

// Get the active effects and check if it's empty
if (TArray<FActiveGameplayEffectHandle> ActiveEffects = ActiveExtensions.FindRef(TargetActor);
!ActiveEffects.IsEmpty())
{
// Get the target ability system component
if (UAbilitySystemComponent* const AbilitySystemComponent = ModularFeaturesHelper::GetAbilitySystemComponentByActor(TargetActor))
{
UE_LOG(LogGameplayFeaturesExtraActions, Display, TEXT("%s: Removing effects from Actor %s."), *FString(__func__), *TargetActor->GetName());

// Iterate through the active effects and remove the specified effect by its effect handle if its valid
for (const FActiveGameplayEffectHandle& EffectHandle : ActiveEffects)
{
if (EffectHandle.IsValid())
Expand Down
Loading

0 comments on commit 07f3b2f

Please sign in to comment.