Fix ability input system and more

master
MostExcellent 2024-10-24 15:16:02 -07:00
parent 66995bc486
commit 021f30632a
9 changed files with 398 additions and 12 deletions

View File

@ -0,0 +1,37 @@
// Copyright
#include "AbilitySystem/Abilities/VRGameplayAbility.h"
#include "AbilitySystemComponent.h"
UVRGameplayAbility::UVRGameplayAbility()
{
ActivationPolicy = EVRAbilityActivationPolicy::OnInputTriggered;
}
void UVRGameplayAbility::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)
{
Super::OnGiveAbility(ActorInfo, Spec);
if (ActivationPolicy == EVRAbilityActivationPolicy::OnGiven)
{
if (ActorInfo && !Spec.IsActive())
{
ActorInfo->AbilitySystemComponent->TryActivateAbility(Spec.Handle);
}
}
}
void UVRGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{
Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
if (ActivationPolicy == EVRAbilityActivationPolicy::OnGiven)
{
if (ActorInfo)
{
ActorInfo->AbilitySystemComponent->ClearAbility(Handle);
}
}
}

View File

@ -2,3 +2,167 @@
#include "AbilitySystem/VRAbilitySystemComponent.h" #include "AbilitySystem/VRAbilitySystemComponent.h"
#include "Logging.h"
#include "AbilitySystem/Abilities/VRGameplayAbility.h"
#include "AbilitySystem/StartupData/VRStartupAbilitySystemData.h"
UVRAbilitySystemComponent::UVRAbilitySystemComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UVRAbilitySystemComponent::ApplyStartupData()
{
if (StartupData)
{
StartupData->GiveToAbilitySystemComponent(this, DefaultStartingAbilityLevel);
}
UE_LOG(VRGAS_Log, Error, TEXT("UVRAbilitySystemComponent::ApplyStartupData - No Startup Data found!"))
}
void UVRAbilitySystemComponent::InputTagPressed(FGameplayTag& InTag)
{
if (!InTag.IsValid()) return;
FScopedAbilityListLock ActiveScopeLoc(*this);
for (FGameplayAbilitySpec& AbilitySpec : GetActivatableAbilities())
{
if (AbilitySpec.Ability && AbilitySpec.DynamicAbilityTags.HasTagExact(InTag))
{
InputPressedSpecHandles.AddUnique(AbilitySpec.Handle);
InputHeldSpecHandles.AddUnique(AbilitySpec.Handle);
}
}
}
void UVRAbilitySystemComponent::InputTagReleased(FGameplayTag& InTag)
{
if (!InTag.IsValid()) return;
FScopedAbilityListLock ActiveScopeLoc(*this);
for (FGameplayAbilitySpec& AbilitySpec : GetActivatableAbilities())
{
if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InTag)))
{
InputReleasedSpecHandles.AddUnique(AbilitySpec.Handle);
InputHeldSpecHandles.Remove(AbilitySpec.Handle);
}
}
}
// We're doing the Lyra approach
void UVRAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused)
{
// TODO: Add tag that blocks all abilities
TArray<FGameplayAbilitySpecHandle> AbilitiesToActivate;
// Handle held abilities
for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : InputHeldSpecHandles)
{
if (const FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(AbilitySpecHandle))
{
if (AbilitySpec->Ability && !AbilitySpec->IsActive())
{
const UVRGameplayAbility* AbilityCDO = CastChecked<UVRGameplayAbility>(AbilitySpec->Ability);
if (AbilityCDO->GetActivationPolicy() == EVRAbilityActivationPolicy::OnInputHeld)
{
AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
}
}
}
}
for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : InputPressedSpecHandles)
{
if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(AbilitySpecHandle))
{
if (AbilitySpec->Ability)
{
AbilitySpec->InputPressed;
if (AbilitySpec->IsActive())
{
AbilitySpecInputPressed(*AbilitySpec);
}
else
{
// ReSharper disable once CppTooWideScopeInitStatement
const UVRGameplayAbility* AbilityCDO = CastChecked<UVRGameplayAbility>(AbilitySpec->Ability);
if (AbilityCDO->GetActivationPolicy() == EVRAbilityActivationPolicy::OnInputTriggered)
{
AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
}
}
}
}
}
// Activate all abilities to be activated
for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : AbilitiesToActivate)
{
TryActivateAbility(AbilitySpecHandle);
}
// Handle released ability inputs
for (FGameplayAbilitySpecHandle& AbilitySpecHandle : InputReleasedSpecHandles)
{
if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(AbilitySpecHandle))
{
if (AbilitySpec->Ability)
{
AbilitySpec->InputPressed = false;
if (AbilitySpec->IsActive())
{
AbilitySpecInputReleased(*AbilitySpec);
}
}
}
}
// Clear cached ability handles, as in Lyra
InputPressedSpecHandles.Empty();
InputReleasedSpecHandles.Empty();
}
void UVRAbilitySystemComponent::ClearAbilityInput()
{
InputPressedSpecHandles.Empty();
InputReleasedSpecHandles.Empty();
InputHeldSpecHandles.Empty();
}
void UVRAbilitySystemComponent::AbilitySpecInputPressed(FGameplayAbilitySpec& Spec)
{
Super::AbilitySpecInputPressed(Spec);
// Do like Lyra
if (Spec.IsActive())
{
// Invoke the InputPressed event.
// This is not replicated here.
// If someone is listening, they may replicate the InputPressed event to the server.
InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey());
}
}
void UVRAbilitySystemComponent::AbilitySpecInputReleased(FGameplayAbilitySpec& Spec)
{
Super::AbilitySpecInputReleased(Spec);
if (Spec.IsActive())
{
// Invoke the InputReleased event.
// This is not replicated here.
// If someone is listening, they may replicate the InputReleased event to the server.
InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey());
}
}

View File

@ -2,3 +2,98 @@
#include "Player/VRPlayerController.h" #include "Player/VRPlayerController.h"
#include "AbilitySystemGlobals.h"
#include "EnhancedInputSubsystems.h"
#include "Logging.h"
#include "AbilitySystem/VRAbilitySystemComponent.h"
#include "Input/VRInputComponent.h"
AVRPlayerController::AVRPlayerController()
{
bReplicates = true;
}
void AVRPlayerController::PostProcessInput(const float DeltaTime, const bool bGamePaused)
{
if (UVRAbilitySystemComponent* VRAbilitySystemComponent = GetVRAbilitySystemComponent())
{
VRAbilitySystemComponent->ProcessAbilityInput(DeltaTime, bGamePaused);
}
Super::PostProcessInput(DeltaTime, bGamePaused);
}
void AVRPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
// We could check the subsystem instead of doing an if statement
// check(Subsystem);
if (InputMappingContext)
{
Subsystem->AddMappingContext(InputMappingContext, 0);
}
else
{
UE_LOG(VRGAS_Log, Error, TEXT("AVRPlayerController::SetupInputComponent - Input Mapping Context not found!"))
}
if (UVRInputComponent* VRInputComponent = Cast<UVRInputComponent>(InputComponent))
{
VRInputComponent->BindAbilityActions(InputConfig, this,
&ThisClass::Input_AbilityTagPressed, &ThisClass::Input_AbilityTagReleased);
}
else
{
UE_LOG(VRGAS_Log, Error, TEXT("AVRPlayerController::SetupInputComponent - Input Component is not of VRGAS type!"))
}
}
void AVRPlayerController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
CachedAbilitySystemComponent = Cast<UVRAbilitySystemComponent>(
UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(GetPawn()));
}
UAbilitySystemComponent* AVRPlayerController::GetAbilitySystemComponent()
{
if (!CachedAbilitySystemComponent.IsValid())
{
CachedAbilitySystemComponent = Cast<UVRAbilitySystemComponent>(
UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(GetPawn()));
if (!CachedAbilitySystemComponent.IsValid()) return nullptr;
}
return CachedAbilitySystemComponent.Get();
}
UVRAbilitySystemComponent* AVRPlayerController::GetVRAbilitySystemComponent()
{
return Cast<UVRAbilitySystemComponent>(GetAbilitySystemComponent());
}
void AVRPlayerController::Input_AbilityTagPressed(FGameplayTag InTag)
{
if (!GetVRAbilitySystemComponent())
{
UE_LOG(VRGAS_Log, Error, TEXT("AVRPlayerController::Input_AbilityTagPressed - No Vagabond Rose ASC present!"))
}
GetVRAbilitySystemComponent()->InputTagPressed(InTag);
}
void AVRPlayerController::Input_AbilityTagReleased(FGameplayTag InTag)
{
if (!GetVRAbilitySystemComponent())
{
UE_LOG(VRGAS_Log, Error, TEXT("AVRPlayerController::Input_AbilityTagReleased - No Vagabond Rose ASC present!"))
}
GetVRAbilitySystemComponent()->InputTagReleased(InTag);
}

View File

@ -4,7 +4,7 @@
bool FVRAbilitySet::IsValid() const bool FVRAbilitySet::IsValid() const
{ {
return AbilityClass; return AbilityClass != nullptr;
} }
bool FVRAbilitySet::IsValidInput() const bool FVRAbilitySet::IsValidInput() const

View File

@ -0,0 +1,38 @@
// Copyright
#pragma once
#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "VRGameplayAbility.generated.h"
UENUM(BlueprintType)
enum class EVRAbilityActivationPolicy : uint8
{
OnInputTriggered,
OnInputHeld,
OnGiven
};
/**
*
*/
UCLASS()
class VRGAS_API UVRGameplayAbility : public UGameplayAbility
{
GENERATED_BODY()
public:
UVRGameplayAbility();
EVRAbilityActivationPolicy GetActivationPolicy() const { return ActivationPolicy; }
protected:
//~ Begin UGameplayAbility Interface
virtual void OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override;
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
//~ End UGameplayAbility Interface
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Activation")
EVRAbilityActivationPolicy ActivationPolicy;
};

View File

@ -6,9 +6,10 @@
#include "AbilitySystemComponent.h" #include "AbilitySystemComponent.h"
#include "VRAbilitySystemComponent.generated.h" #include "VRAbilitySystemComponent.generated.h"
DECLARE_MULTICAST_DELEGATE_OneParam(FEffectAssetTags, const FGameplayTagContainer& /*AssetTags*/); // DECLARE_MULTICAST_DELEGATE_OneParam(FEffectAssetTags, const FGameplayTagContainer& /*AssetTags*/);
DECLARE_MULTICAST_DELEGATE(FAbilitiesGiven); // DECLARE_MULTICAST_DELEGATE(FAbilitiesGiven);
class UVRStartupAbilitySystemData;
/** /**
* *
*/ */
@ -18,13 +19,50 @@ class VRGAS_API UVRAbilitySystemComponent : public UAbilitySystemComponent
GENERATED_BODY() GENERATED_BODY()
public: public:
void AbilityActorInfoSet(); UVRAbilitySystemComponent(const FObjectInitializer& ObjectInitializer);
// void AbilityActorInfoSet();
FEffectAssetTags EffectAssetTags;
FAbilitiesGiven OnAbilitiesGiven;
// FEffectAssetTags EffectAssetTags;
// FAbilitiesGiven OnAbilitiesGiven;
#pragma region PublicStartup
UPROPERTY(BlueprintReadOnly, Category = "Startup Data")
bool bStartupAbilitiesGiven = false; bool bStartupAbilitiesGiven = false;
virtual void ApplyStartupData();
#pragma endregion
// Add startup abilities // Add startup abilities
#pragma region PublicInput
// Handle pressed input
virtual void InputTagPressed(FGameplayTag& InTag);
// Handle released input
virtual void InputTagReleased(FGameplayTag& InTag);
void ProcessAbilityInput(float DeltaTime, bool bGamePaused);
void ClearAbilityInput();
#pragma endregion
protected:
#pragma region ProtectedInput
virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& Spec) override;
virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& Spec) override;
// Handles to abilities that had their input pressed this frame.
TArray<FGameplayAbilitySpecHandle> InputPressedSpecHandles;
// Handles to abilities that had their input released this frame.
TArray<FGameplayAbilitySpecHandle> InputReleasedSpecHandles;
// Handles to abilities that have their input held.
TArray<FGameplayAbilitySpecHandle> InputHeldSpecHandles;
#pragma endregion
#pragma region ProtectedStartup
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Startup Data")
TObjectPtr<UVRStartupAbilitySystemData> StartupData;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Startup Data", meta = (ClampMin = 1))
int DefaultStartingAbilityLevel = 1;
#pragma endregion
}; };

View File

@ -13,6 +13,7 @@ class VRGAS_API UVRInputComponent : public UEnhancedInputComponent
{ {
GENERATED_BODY() GENERATED_BODY()
public:
template <class UserClass, typename FuncType> template <class UserClass, typename FuncType>
void BindNativeActions(const UVRInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, void BindNativeActions(const UVRInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent,
UserClass* Object,FuncType Func, bool bLogNotFound = true); UserClass* Object,FuncType Func, bool bLogNotFound = true);
@ -25,7 +26,7 @@ template <class UserClass, typename FuncType>
void UVRInputComponent::BindNativeActions(const UVRInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, void UVRInputComponent::BindNativeActions(const UVRInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent,
UserClass* Object,FuncType Func, const bool bLogNotFound) UserClass* Object,FuncType Func, const bool bLogNotFound)
{ {
check(InputConfig) check(InputConfig);
if (UInputAction* Action = InputConfig->FindNativeInputActionForTag(InputTag, bLogNotFound)) if (UInputAction* Action = InputConfig->FindNativeInputActionForTag(InputTag, bLogNotFound))
{ {
BindAction(Action, TriggerEvent, Object, Func); BindAction(Action, TriggerEvent, Object, Func);
@ -33,9 +34,9 @@ void UVRInputComponent::BindNativeActions(const UVRInputConfig* InputConfig, con
} }
template <class UserClass, typename PressedFuncType, typename ReleasedFuncType> template <class UserClass, typename PressedFuncType, typename ReleasedFuncType>
void UVRInputComponent::BindAbilityActions(const UVRInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc); void UVRInputComponent::BindAbilityActions(const UVRInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc)
{ {
check(InputConfig) check(InputConfig);
for (const FVRTagInputBinding& Binding : InputConfig->AbilityInputActions) for (const FVRTagInputBinding& Binding : InputConfig->AbilityInputActions)
{ {
if (Binding.IsValid()) if (Binding.IsValid())

View File

@ -6,6 +6,8 @@
#include "GameFramework/PlayerController.h" #include "GameFramework/PlayerController.h"
#include "VRPlayerController.generated.h" #include "VRPlayerController.generated.h"
class UVRAbilitySystemComponent;
struct FGameplayTag;
class UVRInputConfig; class UVRInputConfig;
class UInputMappingContext; class UInputMappingContext;
class UAbilitySystemComponent; class UAbilitySystemComponent;
@ -21,6 +23,10 @@ class VRGAS_API AVRPlayerController : public APlayerController
public: public:
AVRPlayerController(); AVRPlayerController();
//~ Begin APlayerController Interface
virtual void PostProcessInput(const float DeltaTime, const bool bGamePaused) override;
//~ End APlayerContoller Interface
protected: protected:
// TODO: Implement controller // TODO: Implement controller
virtual void SetupInputComponent() override; virtual void SetupInputComponent() override;
@ -40,5 +46,11 @@ protected:
UFUNCTION(BlueprintPure, Category = "Ability System", meta = (HideSelfPin)) UFUNCTION(BlueprintPure, Category = "Ability System", meta = (HideSelfPin))
UAbilitySystemComponent* GetAbilitySystemComponent(); UAbilitySystemComponent* GetAbilitySystemComponent();
UFUNCTION(BlueprintPure, Category = "Ability System", meta = (HideSelfPin))
UVRAbilitySystemComponent* GetVRAbilitySystemComponent();
void Input_AbilityTagPressed(FGameplayTag InTag);
void Input_AbilityTagReleased(FGameplayTag InTag);
#pragma endregion #pragma endregion
}; };

View File

@ -2,6 +2,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "GameplayTagContainer.h" #include "GameplayTagContainer.h"
#include "VRGASTypes.generated.h"
class UGameplayAbility; class UGameplayAbility;
@ -17,7 +18,7 @@ struct FVRAbilitySet
TSubclassOf<UGameplayAbility> AbilityClass; TSubclassOf<UGameplayAbility> AbilityClass;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
uint32 AbilityLevel = 1.f; int AbilityLevel = 1;
bool IsValid() const; bool IsValid() const;