Input buffer changed from a subsystem to an extension of the input component.

This commit is contained in:
Jamie Greunbaum 2023-09-21 20:32:29 -04:00
parent 74411baaea
commit a4913db597
4 changed files with 55 additions and 69 deletions

View File

@ -3,9 +3,8 @@
#include "Components/ComboManagerComponent.h" #include "Components/ComboManagerComponent.h"
#include "ComboInputAssets.h" #include "ComboInputAssets.h"
#include "EnhancedInputComponent.h"
#include "InputBufferLocalPlayerSubsystem.h"
#include "Components/InputBufferComponent.h"
#include "Engine/LocalPlayer.h" #include "Engine/LocalPlayer.h"
#include "GameFramework/Character.h" #include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
@ -20,22 +19,6 @@ UComboManagerComponent::UComboManagerComponent()
PrimaryComponentTick.bCanEverTick = false; PrimaryComponentTick.bCanEverTick = false;
} }
void UComboManagerComponent::BeginPlay()
{
Super::BeginPlay();
// If this component's owner is the player character or controller, attach it to the subsystem.
APlayerController *PlayerController = UGameplayStatics::GetPlayerController(this, 0);
if (this->GetOwner() == PlayerController)
{
UEnhancedInputComponent *InputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent);
checkf(InputComponent, TEXT("Discovered player input component is not of type %s."), *UEnhancedInputComponent::StaticClass()->GetName());
UInputBufferLocalPlayerSubsystem *InputBufferSubsystem = PlayerController->GetLocalPlayer()->GetSubsystem<UInputBufferLocalPlayerSubsystem>();
InputBufferSubsystem->AttachComboManager(this, InputComponent);
}
}
void UComboManagerComponent::HandleComboInput(const UComboInputAsset *Input, const EComboActionTriggerEvent &TriggerEvent) void UComboManagerComponent::HandleComboInput(const UComboInputAsset *Input, const EComboActionTriggerEvent &TriggerEvent)
{ {
@ -105,8 +88,10 @@ void UComboManagerComponent::ActivateComboAction(const UComboInputAsset *Input)
void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr<const UComboInputAsset> Unlock) void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr<const UComboInputAsset> Unlock)
{ {
APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0); APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0);
UInputBufferLocalPlayerSubsystem *Subsystem = Controller->GetLocalPlayer()->GetSubsystem<UInputBufferLocalPlayerSubsystem>(); if (UInputBufferComponent *InputComponent = Cast<UInputBufferComponent>(Controller->InputComponent))
Subsystem->UnlockComboInput(Unlock); {
InputComponent->UnlockComboInput(Unlock);
}
} }
void UComboManagerComponent::ReleaseComboAction(const class UComboInputAsset *Input) void UComboManagerComponent::ReleaseComboAction(const class UComboInputAsset *Input)

View File

@ -1,22 +1,24 @@
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. // ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
#include "InputBufferLocalPlayerSubsystem.h" #include "Components/InputBufferComponent.h"
#include "ComboInputAssets.h" #include "ComboInputAssets.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Components/ComboManagerComponent.h" #include "Components/ComboManagerComponent.h"
#include "GlobalSettings/InputBufferSubsystemGlobalSettings.h" #include "GlobalSettings/InputBufferSubsystemGlobalSettings.h"
DEFINE_LOG_CATEGORY(LogInputBufferLocalPlayerSubsystem); DEFINE_LOG_CATEGORY(LogInputBufferComponent);
void UInputBufferLocalPlayerSubsystem::Initialize(FSubsystemCollectionBase &Collection) void UInputBufferComponent::BeginPlay()
{ {
Super::Initialize(Collection); Super::BeginPlay();
}
void UInputBufferLocalPlayerSubsystem::AttachComboManager(UComboManagerComponent *ComboManager, UEnhancedInputComponent *InputComponent) if (APlayerController *PlayerController = UGameplayStatics::GetPlayerController(this, 0))
{
if (UComboManagerComponent *ComboManager = PlayerController->GetComponentByClass<UComboManagerComponent>())
{ {
// Get the player character and try to connect to its combo manager. // Get the player character and try to connect to its combo manager.
this->OnNewComboInput.BindUObject(ComboManager, &UComboManagerComponent::HandleComboInput); this->OnNewComboInput.BindUObject(ComboManager, &UComboManagerComponent::HandleComboInput);
@ -33,13 +35,15 @@ void UInputBufferLocalPlayerSubsystem::AttachComboManager(UComboManagerComponent
} }
for (const UInputAction *InputAction : InputActionsToBind) for (const UInputAction *InputAction : InputActionsToBind)
{ {
InputComponent->BindAction(InputAction, ETriggerEvent::Started, this, &UInputBufferLocalPlayerSubsystem::AddActionToBuffer, InputAction); this->BindAction(InputAction, ETriggerEvent::Started, this, &UInputBufferComponent::AddActionToBuffer, InputAction);
InputComponent->BindAction(InputAction, ETriggerEvent::Completed, this, &UInputBufferLocalPlayerSubsystem::ExpireAction, InputAction); this->BindAction(InputAction, ETriggerEvent::Completed, this, &UInputBufferComponent::ExpireAction, InputAction);
}
}
} }
} }
void UInputBufferLocalPlayerSubsystem::AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action) void UInputBufferComponent::AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action)
{ {
this->MostRecentActions.Add(Action); this->MostRecentActions.Add(Action);
this->ExpiringActions.Remove(Action); this->ExpiringActions.Remove(Action);
@ -56,9 +60,9 @@ void UInputBufferLocalPlayerSubsystem::AddActionToBuffer(const FInputActionValue
} }
} }
this->GetWorld()->GetTimerManager().SetTimer(this->MultiPressTimerHandle, this, &UInputBufferLocalPlayerSubsystem::ClearMultiPresses, Settings->MultiPressTimerLength); this->GetWorld()->GetTimerManager().SetTimer(this->MultiPressTimerHandle, this, &UInputBufferComponent::ClearMultiPresses, Settings->MultiPressTimerLength);
} }
void UInputBufferLocalPlayerSubsystem::ClearMultiPresses() void UInputBufferComponent::ClearMultiPresses()
{ {
#if WITH_EDITOR #if WITH_EDITOR
TArray<FString> ActionNames; TArray<FString> ActionNames;
@ -66,12 +70,12 @@ void UInputBufferLocalPlayerSubsystem::ClearMultiPresses()
{ {
ActionNames.Add(Action->GetName()); ActionNames.Add(Action->GetName());
} }
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("Multi-press buffer cleared (%s)"), *FString::Join(ActionNames, TEXT(" | "))); UE_LOG(LogInputBufferComponent, Verbose, TEXT("Multi-press buffer cleared (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
#endif #endif
this->MostRecentActions.Empty(); this->MostRecentActions.Empty();
} }
void UInputBufferLocalPlayerSubsystem::ActivateComboInput(const UComboInputAsset *ComboInput) void UInputBufferComponent::ActivateComboInput(const UComboInputAsset *ComboInput)
{ {
checkf(ComboInput, TEXT("Invalid %s."), *UComboInputAsset::StaticClass()->GetName()); checkf(ComboInput, TEXT("Invalid %s."), *UComboInputAsset::StaticClass()->GetName());
@ -101,7 +105,7 @@ void UInputBufferLocalPlayerSubsystem::ActivateComboInput(const UComboInputAsset
this->OnNewComboInput.Execute(ComboInput, EComboActionTriggerEvent::Released); this->OnNewComboInput.Execute(ComboInput, EComboActionTriggerEvent::Released);
} }
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s is active."), *ComboInput->ComboInputName.ToString()); UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is active."), *ComboInput->ComboInputName.ToString());
} }
else else
{ {
@ -109,32 +113,32 @@ void UInputBufferLocalPlayerSubsystem::ActivateComboInput(const UComboInputAsset
} }
} }
void UInputBufferLocalPlayerSubsystem::HoldComboInput(const UComboInputAsset *ComboInput) void UInputBufferComponent::HoldComboInput(const UComboInputAsset *ComboInput)
{ {
this->InputBufferHold = ComboInput; this->InputBufferHold = ComboInput;
UE_SUPPRESS(LogInputBufferLocalPlayerSubsystem, Verbose, UE_SUPPRESS(LogInputBufferComponent, Verbose,
{ {
if (this->LockedComboInputs.Contains(ComboInput)) if (this->LockedComboInputs.Contains(ComboInput))
{ {
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s is locked and won't be activated yet."), *ComboInput->ComboInputName.ToString()); UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is locked and won't be activated yet."), *ComboInput->ComboInputName.ToString());
} }
else else
{ {
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s added to buffer."), *ComboInput->ComboInputName.ToString()); UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s added to buffer."), *ComboInput->ComboInputName.ToString());
} }
} }
); );
} }
void UInputBufferLocalPlayerSubsystem::LockComboInput(const UComboInputAsset *Input) void UInputBufferComponent::LockComboInput(const UComboInputAsset *Input)
{ {
this->LockedComboInputs.Emplace(Input); this->LockedComboInputs.Emplace(Input);
} }
void UInputBufferLocalPlayerSubsystem::UnlockComboInput(const UComboInputAsset *Unlocked) void UInputBufferComponent::UnlockComboInput(const UComboInputAsset *Unlocked)
{ {
// Remove the newly-unlocked asset from the locked combo inputs. // Remove the newly-unlocked asset from the locked combo inputs.
UE_CLOG(this->LockedComboInputs.Contains(Unlocked), LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s has unlocked."), *Unlocked->ComboInputName.ToString()); UE_CLOG(this->LockedComboInputs.Contains(Unlocked), LogInputBufferComponent, Verbose, TEXT("%s has unlocked."), *Unlocked->ComboInputName.ToString());
this->LockedComboInputs.Remove(Unlocked); this->LockedComboInputs.Remove(Unlocked);
// Check if the newly unlocked combo input is in the hold. // Check if the newly unlocked combo input is in the hold.
@ -150,11 +154,11 @@ void UInputBufferLocalPlayerSubsystem::UnlockComboInput(const UComboInputAsset *
this->ActivateComboInput(HeldAsset); this->ActivateComboInput(HeldAsset);
} }
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s has expired."), *OriginalActive->ComboInputName.ToString()); UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has expired."), *OriginalActive->ComboInputName.ToString());
} }
} }
void UInputBufferLocalPlayerSubsystem::ExpireAction(const FInputActionValue &Value, const class UInputAction *Action) void UInputBufferComponent::ExpireAction(const FInputActionValue &Value, const class UInputAction *Action)
{ {
// Only send a release event if we haven't already, i.e. if the combo input associated // Only send a release event if we haven't already, i.e. if the combo input associated
// with the action is not already buffered for another future activation. // with the action is not already buffered for another future activation.
@ -166,21 +170,21 @@ void UInputBufferLocalPlayerSubsystem::ExpireAction(const FInputActionValue &Val
// Prepare to expire any buffered combo inputs // Prepare to expire any buffered combo inputs
this->ExpiringActions.Add(Action); this->ExpiringActions.Add(Action);
const UInputBufferSubsystemGlobalSettings *Settings = GetDefault<UInputBufferSubsystemGlobalSettings>(); const UInputBufferSubsystemGlobalSettings *Settings = GetDefault<UInputBufferSubsystemGlobalSettings>();
this->GetWorld()->GetTimerManager().SetTimer(this->InputReleaseExpirationTimerHandle, this, &UInputBufferLocalPlayerSubsystem::ExpireBufferedActions, Settings->InputReleaseExpirationTimerLength); this->GetWorld()->GetTimerManager().SetTimer(this->InputReleaseExpirationTimerHandle, this, &UInputBufferComponent::ExpireBufferedActions, Settings->InputReleaseExpirationTimerLength);
} }
void UInputBufferLocalPlayerSubsystem::ExpireBufferedActions() void UInputBufferComponent::ExpireBufferedActions()
{ {
// Only bother dealing with this if there's something to deal with in the first place. // Only bother dealing with this if there's something to deal with in the first place.
if (!this->ExpiringActions.IsEmpty()) if (!this->ExpiringActions.IsEmpty())
{ {
UE_SUPPRESS(LogInputBufferLocalPlayerSubsystem, Verbose, UE_SUPPRESS(LogInputBufferComponent, Verbose,
{ {
TArray<FString> ActionNames; TArray<FString> ActionNames;
for (const UInputAction *Action : this->ExpiringActions) for (const UInputAction *Action : this->ExpiringActions)
{ {
ActionNames.Add(Action->GetName()); ActionNames.Add(Action->GetName());
} }
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("Released actions expired (%s)"), *FString::Join(ActionNames, TEXT(" | "))); UE_LOG(LogInputBufferComponent, Verbose, TEXT("Released actions expired (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
} }
); );
@ -192,7 +196,7 @@ void UInputBufferLocalPlayerSubsystem::ExpireBufferedActions()
{ {
if (this->InputBufferHold->MatchesInputAction(Action)) if (this->InputBufferHold->MatchesInputAction(Action))
{ {
UE_LOG(LogInputBufferLocalPlayerSubsystem, Verbose, TEXT("%s has been cancelled."), *this->InputBufferHold->ComboInputName.ToString()); UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has been cancelled."), *this->InputBufferHold->ComboInputName.ToString());
this->InputBufferHold = nullptr; this->InputBufferHold = nullptr;
break; break;
} }

View File

@ -42,7 +42,6 @@ class COMBOINPUT_API UComboManagerComponent : public UActorComponent
public: public:
UComboManagerComponent(); UComboManagerComponent();
virtual void BeginPlay() override;
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void HandleComboInput(const class UComboInputAsset *Input, const EComboActionTriggerEvent &TriggerEvent); void HandleComboInput(const class UComboInputAsset *Input, const EComboActionTriggerEvent &TriggerEvent);

View File

@ -3,11 +3,11 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputComponent.h"
#include "InputBufferLocalPlayerSubsystem.generated.h" #include "InputBufferComponent.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferLocalPlayerSubsystem, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferComponent, Log, All);
DECLARE_DELEGATE_TwoParams(FNewComboInput, const class UComboInputAsset*, const EComboActionTriggerEvent &); DECLARE_DELEGATE_TwoParams(FNewComboInput, const class UComboInputAsset*, const EComboActionTriggerEvent &);
@ -16,14 +16,12 @@ DECLARE_DELEGATE_TwoParams(FNewComboInput, const class UComboInputAsset*, const
* Subsystem that handles input buffering, and passing the resulting actions to the player's ComboManagerComponent. * Subsystem that handles input buffering, and passing the resulting actions to the player's ComboManagerComponent.
*/ */
UCLASS() UCLASS()
class COMBOINPUT_API UInputBufferLocalPlayerSubsystem : public UEnhancedInputLocalPlayerSubsystem class COMBOINPUT_API UInputBufferComponent : public UEnhancedInputComponent
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
virtual void Initialize(FSubsystemCollectionBase &Collection) override; virtual void BeginPlay() override;
void AttachComboManager(class UComboManagerComponent *ComboManager, class UEnhancedInputComponent *InputComponent);
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void LockComboInput(const class UComboInputAsset *Input); void LockComboInput(const class UComboInputAsset *Input);