From cd4708449f2be6b6c646cf0d23b0965f822d1557 Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Sun, 10 Sep 2023 01:47:21 -0400 Subject: [PATCH] - Buffered inputs are no longer handled by a component on the PlayerController, but by a LocalPlayerSubsystem instead. - Combo manager connects to this subsystem entirely on its own when its owner is the player character. --- .../ComboInput/Private/ComboInputAssets.cpp | 6 + .../Components/ComboManagerComponent.cpp | 33 +-- .../Components/InputBufferComponent.cpp | 189 ------------------ .../InputBufferSubsystemGlobalSettings.cpp | 6 + .../InputBufferLocalPlayerSubsystem.cpp | Bin 0 -> 13902 bytes .../Interfaces/ComboHandlerInterface.cpp | 17 -- Source/ComboInput/Public/ComboInputAssets.h | 90 +++++++++ .../Public/Components/ComboManagerComponent.h | 40 +--- .../Public/Components/InputBufferComponent.h | 118 ----------- .../InputBufferSubsystemGlobalSettings.h | 32 +++ .../Public/InputBufferLocalPlayerSubsystem.h | Bin 0 -> 3954 bytes .../Public/Interfaces/ComboHandlerInterface.h | 32 --- 12 files changed, 158 insertions(+), 405 deletions(-) create mode 100644 Source/ComboInput/Private/ComboInputAssets.cpp delete mode 100644 Source/ComboInput/Private/Components/InputBufferComponent.cpp create mode 100644 Source/ComboInput/Private/GlobalSettings/InputBufferSubsystemGlobalSettings.cpp create mode 100644 Source/ComboInput/Private/InputBufferLocalPlayerSubsystem.cpp delete mode 100644 Source/ComboInput/Private/Interfaces/ComboHandlerInterface.cpp create mode 100644 Source/ComboInput/Public/ComboInputAssets.h delete mode 100644 Source/ComboInput/Public/Components/InputBufferComponent.h create mode 100644 Source/ComboInput/Public/GlobalSettings/InputBufferSubsystemGlobalSettings.h create mode 100644 Source/ComboInput/Public/InputBufferLocalPlayerSubsystem.h delete mode 100644 Source/ComboInput/Public/Interfaces/ComboHandlerInterface.h diff --git a/Source/ComboInput/Private/ComboInputAssets.cpp b/Source/ComboInput/Private/ComboInputAssets.cpp new file mode 100644 index 0000000..a57affd --- /dev/null +++ b/Source/ComboInput/Private/ComboInputAssets.cpp @@ -0,0 +1,6 @@ +// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. + +#include "ComboInputAssets.h" + + + diff --git a/Source/ComboInput/Private/Components/ComboManagerComponent.cpp b/Source/ComboInput/Private/Components/ComboManagerComponent.cpp index 074c629..00ae124 100644 --- a/Source/ComboInput/Private/Components/ComboManagerComponent.cpp +++ b/Source/ComboInput/Private/Components/ComboManagerComponent.cpp @@ -2,8 +2,13 @@ #include "Components/ComboManagerComponent.h" -#include "Components/InputBufferComponent.h" -#include "Interfaces/ComboHandlerInterface.h" +#include "ComboInputAssets.h" +#include "EnhancedInputComponent.h" +#include "InputBufferLocalPlayerSubsystem.h" + +#include "Engine/LocalPlayer.h" +#include "GameFramework/Character.h" +#include "Kismet/GameplayStatics.h" DEFINE_LOG_CATEGORY(LogComboManagerComponent); @@ -18,20 +23,22 @@ UComboManagerComponent::UComboManagerComponent() void UComboManagerComponent::BeginPlay() { Super::BeginPlay(); - - const AActor *OwningActor = this->GetOwner(); - if (const IComboHandlerInterface *ComboHandler = Cast(OwningActor)) + + // If this component's owner is the player character, attach it to the subsystem. + ACharacter *PlayerCharacter = UGameplayStatics::GetPlayerCharacter(this, 0); + if (this->GetOwner() == PlayerCharacter) { - if (UInputBufferComponent *InputBuffer = IComboHandlerInterface::Execute_GetInputBuffer(OwningActor)) - { - this->AttachedInputBuffer = InputBuffer; - this->AttachedInputBuffer->NewComboInput.BindUObject(this, &UComboManagerComponent::ComboInputReceived); - } + APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0); + UEnhancedInputComponent *InputComponent = Cast(Controller->InputComponent); + checkf(Controller, TEXT("Discovered controller is not a %s type."), *UEnhancedInputComponent::StaticClass()->GetName()); + + UInputBufferLocalPlayerSubsystem *InputBufferSubsystem = Controller->GetLocalPlayer()->GetSubsystem(); + InputBufferSubsystem->AttachComboManager(this, InputComponent); } } -void UComboManagerComponent::ComboInputReceived(const UComboInputAsset *Input) +void UComboManagerComponent::ActivateComboInput(const UComboInputAsset *Input) { /************ DEBUG ************/ for (const TPair, float> &Pair : this->DEBUG__UnlockTimers) @@ -74,7 +81,9 @@ void UComboManagerComponent::ComboInputReceived(const UComboInputAsset *Input) } void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr Unlock) { - this->AttachedInputBuffer->UnlockComboInput(Unlock); + APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0); + UInputBufferLocalPlayerSubsystem *Subsystem = Controller->GetLocalPlayer()->GetSubsystem(); + Subsystem->UnlockComboInput(Unlock); } diff --git a/Source/ComboInput/Private/Components/InputBufferComponent.cpp b/Source/ComboInput/Private/Components/InputBufferComponent.cpp deleted file mode 100644 index 84e6c51..0000000 --- a/Source/ComboInput/Private/Components/InputBufferComponent.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. - -#include "Components/InputBufferComponent.h" - -#include "Components/InputComponent.h" -#include "GameFramework/PlayerController.h" - -DEFINE_LOG_CATEGORY(LogInputBufferComponent); - - -UInputBufferComponent::UInputBufferComponent() -{ - PrimaryComponentTick.bStartWithTickEnabled = false; - PrimaryComponentTick.bTickEvenWhenPaused = false; - PrimaryComponentTick.bCanEverTick = false; -} - -void UInputBufferComponent::BeginPlay() -{ - Super::BeginPlay(); - - // Get all unique EnhancedInput actions bound to combo input actions. - TSet InputActionsToBind; - for (const UComboInputAsset *ComboInput : this->ComboActions) - { - for (const UInputAction *InputAction : ComboInput->ActionGroup) - { - InputActionsToBind.Add(InputAction); - } - } - - APlayerController *Controller = Cast(this->GetOwner()); - checkf(Controller, TEXT("No player controller found as owner of %s"), *this->GetName()); - - if (this->EnhancedInputComponent = Cast(Controller->InputComponent)) - { - // Bind the input actions we found to the buffer management functions. - for (const UInputAction *InputAction : InputActionsToBind) - { - this->EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Started, this, &UInputBufferComponent::AddActionToBuffer, InputAction); - this->EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Completed, this, &UInputBufferComponent::ExpireAction, InputAction); - } - } - else - { - UE_LOG(LogInputBufferComponent, Error, TEXT("Parent of %s is not a UEnhancedInputComponent type."), *this->GetName()); - } -} - - -void UInputBufferComponent::AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action) -{ - this->MostRecentActions.Add(Action); - this->ExpiringActions.Remove(Action); - - // Find any combo input that matches this action, plus buffered actions. - for (const UComboInputAsset *Combo : this->ComboActions) - { - if (Combo->MatchesInputActions(this->MostRecentActions)) - { - this->ActivateComboInput(Combo); - - break; - } - } - - this->GetWorld()->GetTimerManager().SetTimer(this->MultiPressTimerHandle, this, &UInputBufferComponent::ClearMultiPresses, this->MultiPressTimerLength); -} -void UInputBufferComponent::ClearMultiPresses() -{ -#if WITH_EDITOR - TArray ActionNames; - for (const UInputAction *Action : this->MostRecentActions) - { - ActionNames.Add(Action->GetName()); - } - UE_LOG(LogInputBufferComponent, Verbose, TEXT("Multi-press buffer cleared (%s)"), *FString::Join(ActionNames, TEXT(" | "))); -#endif - this->MostRecentActions.Empty(); -} - -void UInputBufferComponent::ActivateComboInput(const UComboInputAsset *ComboInput) -{ - checkf(ComboInput, TEXT("Invalid UComboInputAsset")); - - // Make this combo input active if it isn't being locked, or if we are - // overwriting a previous combo input with a multi-press combo input. - const bool bMultiPressTimerActive = this->GetWorld()->GetTimerManager().IsTimerActive(this->MultiPressTimerHandle); - const bool bComboInputLocked = this->LockedComboInputs.Contains(ComboInput); - if (bMultiPressTimerActive || !bComboInputLocked) - { - if (!ComboInput->LockedComboInputs.IsEmpty()) - { - // Set the combo input as active, and copy its lock data. - this->InputBufferActive = ComboInput; - this->LockedComboInputs = ComboInput->LockedComboInputs; - - // Make sure the hold is clear if we're coming off of a multi-press action. - if (bMultiPressTimerActive) - { - this->InputBufferHold = nullptr; - } - - UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is active."), *ComboInput->ComboInputName.ToString()); - } - else - { - UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is active and won't lock inputs."), *ComboInput->ComboInputName.ToString()); - } - - this->NewComboInput.Execute(ComboInput); - } - else - { - this->InputBufferHold = ComboInput; - - if (bComboInputLocked) - { - UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is locked and won't be activated yet."), *ComboInput->ComboInputName.ToString()); - } - else - { - UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s added to buffer."), *ComboInput->ComboInputName.ToString()); - } - } -} - -void UInputBufferComponent::UnlockComboInput(const UComboInputAsset *Unlocked) -{ - // Remove the newly-unlocked asset from the locked combo inputs. - UE_CLOG(this->LockedComboInputs.Contains(Unlocked), LogInputBufferComponent, Verbose, TEXT("%s has unlocked."), *Unlocked->ComboInputName.ToString()); - this->LockedComboInputs.Remove(Unlocked); - - // Check if the newly unlocked combo input is in the hold. - if (Unlocked == this->InputBufferHold) - { - const UComboInputAsset *OriginalActive = this->InputBufferActive; - - // Activate the held combo input. - const UComboInputAsset *HeldAsset = this->InputBufferHold; - this->InputBufferHold = nullptr; - if (HeldAsset) - { - this->ActivateComboInput(HeldAsset); - } - - UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has expired."), *OriginalActive->ComboInputName.ToString()); - } -} - -void UInputBufferComponent::ExpireAction(const FInputActionValue &Value, const class UInputAction *Action) -{ - this->ExpiringActions.Add(Action); - this->GetWorld()->GetTimerManager().SetTimer(this->InputReleaseExpirationTimerHandle, this, &UInputBufferComponent::ExpireBufferedActions, this->InputReleaseExpirationTimerLength); -} -void UInputBufferComponent::ExpireBufferedActions() -{ - // Only bother dealing with this if there's something to deal with in the first place. - if (!this->ExpiringActions.IsEmpty()) - { - UE_SUPPRESS(LogInputBufferComponent, Verbose, - { - TArray ActionNames; - for (const UInputAction *Action : this->ExpiringActions) - { - ActionNames.Add(Action->GetName()); - } - UE_LOG(LogInputBufferComponent, Verbose, TEXT("Released actions expired (%s)"), *FString::Join(ActionNames, TEXT(" | "))); - } - ); - - // If there is an action in the hold, check if it's related - // to our current released buttons, and if so cancel it. - if (this->InputBufferHold) - { - for (const UInputAction *Action : this->ExpiringActions) - { - if (this->InputBufferHold->MatchesInputAction(Action)) - { - UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has been cancelled."), *this->InputBufferHold->ComboInputName.ToString()); - this->InputBufferHold = nullptr; - break; - } - } - } - - this->ExpiringActions.Empty(); - } -} diff --git a/Source/ComboInput/Private/GlobalSettings/InputBufferSubsystemGlobalSettings.cpp b/Source/ComboInput/Private/GlobalSettings/InputBufferSubsystemGlobalSettings.cpp new file mode 100644 index 0000000..b45493d --- /dev/null +++ b/Source/ComboInput/Private/GlobalSettings/InputBufferSubsystemGlobalSettings.cpp @@ -0,0 +1,6 @@ +// ©2023 Batty Bovine Productions, LLC. All Rights Reserved. + +#include "GlobalSettings/InputBufferSubsystemGlobalSettings.h" + + + diff --git a/Source/ComboInput/Private/InputBufferLocalPlayerSubsystem.cpp b/Source/ComboInput/Private/InputBufferLocalPlayerSubsystem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dddc854e8db0941e00cbcfb736decf4ccb536407 GIT binary patch literal 13902 zcmdU0ZBH9V5Zvwp&&b)cod58Pk0=@#lOe+{X=Mm0X`S;cQ56L3RWj9a058uik~^MRv8esa{RbNaA| zariQ>)PydngX-wXyskl0T}Vo;ZAa;7w-Zp~D#p3jb5*00sMz|H@OfAbKZ5QneE$lI zZH6^`ufQvIaAytITj7^bkG4D*v;MSpUJBohtjx7PK++EEQG_=$QhpMiL<${PuoHFH z34cO+b;wrL4sAl8Z@Z{q4AGm4a4*`d{Cp{L{#X24i!@I$x`%bgt(;p$HSqUH5A)T* zGUOjXk{0}ZoJZE7?QzfKzK@3@JQzEgIPwNwGJSNBn)z^bwN%T3bZgM_04oh36YX;f z%PE!=QPL*tK$(dqJ&a(a)2jx!A|?)CZ;mAT5f?d9@6uz4cYG=cQ{bBvG=c^BY8ZD2 z-|B~l;TfW(9nPIzOr{19kny?)&1@o$e;ck>ccW8;pce04$tLu<;|!7y!c*wnbaj0^eFl_KP1k^$!okz%QOvew`P6ds z#s~1F!g1lB^+BsU@+Lvf8u;%n*&DyAG++?21zQSmWM= z)g1G>$9PYRNaL^5%0vB^vGNjVLKNS^y4*j|>-|jbJ`^qdee*g`%`DXcrGpA3u5yeO zx$CMYPnDj}=06T=4XJrp>rfB5984ZqDM)oQz&KV@)R1zQ=4tAbmDX7tvx{%t)iK7? zvDAQY<*nc~@1y?n%jt&b%7rn1OuqG0 zG(IL(t$Ds1!^)MlRvHO4)V8}3`I_PVaEHlzX77S+ntDecK{1ryg_WhAJ83K$$I6uFfTcmdNzIS;}sn&FU1>-QE zduU7XV;xD2sm&}lxO>;G&wP43^sKirZiqYVsPGPZNk8Ln9eqCY$%n`=tXL#d`y9hO z#`vHQOTMXxuQ6^3^OqvU2PGS_M*ImY(xPeJR1JvNdrpe*5xkM2>EKNSn6E%ZB|{)H&WCmCgW-9v$?EbdqMhcZiJ7w+Aw#tfVcaQGB>_#b!HiI zc?8X}exNlQ&YHd_P_N{5@>!>mKSSS2H!S4p(C> zRz#2BU)E6U1D%BX@%JvC3XT-ui5+j!mwk}z)dii-BNg#z&ym!6J@k`^M_i8>%L>U93rL(_=eqe;(l~Tc3(?oT#?`m3 z;?3qaspq7+&f9N&BrVbCBx2!F%*nk`MQ1w%)8lPaL(GF}71bZ}jn9qaJSBHutDOdr zvl}~eTIHq{pw)mitab!0+M^hes#-kzQ__jW{5fRP{A|}VR zs(h&z>n^B34(93BakPw_ho@s(@hK}>W)?j@&@d?j0z zn$;O;&HBCw=}hh=NaVA#%`95hocGi+m$OE(N8V}l=IzcmFj5;U;){*MQ&wV!Ug}su zWv)r=GHhFp{7&ma^$tb@XdF8B_ve_EuDPs%E-;Vf#di3pWkVukG)yCYtntO{#sfK7@9D1NiUvzM6(DHQ{E^x z8jC;Mvh~}^yT+`P6p6&@tR6&0@=5QJclWL**-f2&O)nq!^Q;#%!%9Zmgruw^rK>3w z1K){cJulsN=`LHpSp7*mK{|*1AXW^0L=jKJWSq>FU4hapP`k4C#_lsUZCP|5*F8{R zmsQ@| ComboAction; + + // Sequence node to switch to once this action is complete. + UPROPERTY(BlueprintReadOnly, EditAnywhere) + TObjectPtr NextNode; +}; + +UCLASS(BlueprintType) +class COMBOINPUT_API UComboAction : public UDataAsset +{ + GENERATED_BODY() + +public: + // Human-readable name of this combo action. + UPROPERTY(BlueprintReadOnly, EditAnywhere) + FName ActionName; +}; + +UCLASS(BlueprintType) +class COMBOINPUT_API UComboSequenceNode : public UDataAsset +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintReadOnly, EditAnywhere) + TMap ComboBranch; +}; + +UCLASS(BlueprintType) +class COMBOINPUT_API UComboInputAsset : public UDataAsset +{ + GENERATED_BODY() + +public: + bool MatchesInputAction(const class UInputAction* Action) const + { + if (this->ActionGroup.Num() == 1 && this->ActionGroup.Contains(Action)) + { + return true; + } + return false; + } + bool MatchesInputActions(TSet Actions) const + { + if (this->ActionGroup.Num() == Actions.Num()) + { + for (const UInputAction *Action : Actions) + { + if (!this->ActionGroup.Contains(Action)) + { + return false; + } + } + return true; + } + return false; + } + + // Human-readable name of this combo input. + UPROPERTY(BlueprintReadWrite, EditAnywhere) + FName ComboInputName; + + // Combined actions that add up to this combo input when activated + // within a short time of one another. If only one is present, then + // this combo input asset will simply represent that action. + UPROPERTY(BlueprintReadWrite, EditAnywhere) + TSet> ActionGroup; + + // Combo inputs that should be prevented from occurring during this + // action. These will be locked when the action is broadcast, and + // should be unlocked by the receiving actor by sending an unlock + // event. + UPROPERTY(BlueprintReadWrite, EditAnywhere) + TSet> LockedComboInputs; +}; diff --git a/Source/ComboInput/Public/Components/ComboManagerComponent.h b/Source/ComboInput/Public/Components/ComboManagerComponent.h index d364f79..b2d1df7 100644 --- a/Source/ComboInput/Public/Components/ComboManagerComponent.h +++ b/Source/ComboInput/Public/Components/ComboManagerComponent.h @@ -12,41 +12,6 @@ DECLARE_LOG_CATEGORY_EXTERN(LogComboManagerComponent, Log, All); -USTRUCT(BlueprintType) -struct COMBOINPUT_API FComboSequenceAction -{ - GENERATED_BODY() -public: - // Action to perform when the associated combo sequence node is activated. - UPROPERTY(BlueprintReadOnly, EditAnywhere) - TObjectPtr ComboAction; - - // Sequence node to switch to once this action is complete. - UPROPERTY(BlueprintReadOnly, EditAnywhere) - TObjectPtr NextNode; -}; - -UCLASS(BlueprintType) -class COMBOINPUT_API UComboAction : public UDataAsset -{ - GENERATED_BODY() - -public: - // Human-readable name of this combo action. - UPROPERTY(BlueprintReadOnly, EditAnywhere) - FName ActionName; -}; - -UCLASS(BlueprintType) -class COMBOINPUT_API UComboSequenceNode : public UDataAsset -{ - GENERATED_BODY() - -public: - UPROPERTY(BlueprintReadOnly, EditAnywhere) - TMap ComboBranch; -}; - UCLASS(BlueprintType, ClassGroup=(Input), meta=(BlueprintSpawnableComponent)) class COMBOINPUT_API UComboManagerComponent : public UActorComponent { @@ -56,6 +21,9 @@ public: UComboManagerComponent(); virtual void BeginPlay() override; + UFUNCTION(BlueprintCallable) + void ActivateComboInput(const class UComboInputAsset *Input); + protected: UPROPERTY(BlueprintReadOnly, EditDefaultsOnly) TObjectPtr DefaultStartNode; @@ -70,8 +38,6 @@ protected: TMap, float> DEBUG__UnlockTimers; private: - void ComboInputReceived(const class UComboInputAsset *Input); - void BeginNodeTransition(const class UComboSequenceNode *NextNode); void FinishTransition(); diff --git a/Source/ComboInput/Public/Components/InputBufferComponent.h b/Source/ComboInput/Public/Components/InputBufferComponent.h deleted file mode 100644 index 9a809c3..0000000 --- a/Source/ComboInput/Public/Components/InputBufferComponent.h +++ /dev/null @@ -1,118 +0,0 @@ -// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "EnhancedInputComponent.h" -#include "Components/ActorComponent.h" - -#include "InputBufferComponent.generated.h" - -DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferComponent, Log, All); - - -UCLASS(BlueprintType) -class COMBOINPUT_API UComboInputAsset : public UDataAsset -{ - GENERATED_BODY() - -public: - bool MatchesInputAction(const class UInputAction* Action) const - { - if (this->ActionGroup.Num() == 1 && this->ActionGroup.Contains(Action)) - { - return true; - } - return false; - } - bool MatchesInputActions(TSet Actions) const - { - if (this->ActionGroup.Num() == Actions.Num()) - { - for (const UInputAction *Action : Actions) - { - if (!this->ActionGroup.Contains(Action)) - { - return false; - } - } - return true; - } - return false; - } - - // Human-readable name of this combo input. - UPROPERTY(BlueprintReadWrite, EditAnywhere) - FName ComboInputName; - - // Combined actions that add up to this combo input when activated - // within a short time of one another. If only one is present, then - // this combo input asset will simply represent that action. - UPROPERTY(BlueprintReadWrite, EditAnywhere) - TSet> ActionGroup; - - // Combo inputs that should be prevented from occurring during this - // action. These will be locked when the action is broadcast, and - // should be unlocked by the receiving actor by sending an unlock - // event. - UPROPERTY(BlueprintReadWrite, EditAnywhere) - TSet> LockedComboInputs; -}; - - -UCLASS(BlueprintType, ClassGroup=(Input), meta=(BlueprintSpawnableComponent)) -class COMBOINPUT_API UInputBufferComponent : public UActorComponent -{ - GENERATED_BODY() - -public: - UInputBufferComponent(); - virtual void BeginPlay() override; - - UFUNCTION(BlueprintCallable) - void UnlockComboInput(const class UComboInputAsset *Unlocked); - - // List of possible combo inputs that can be taken. A combo input is selected from this list - // either if an action is made while the current combo is inactive, or when the previous - // action expires. - UPROPERTY(BlueprintReadOnly, EditDefaultsOnly) - TSet ComboActions; - - // Length of time after releasing an input to keep the associated combo action buffered before clearing it. - UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, meta=(UIMin="0.0", UIMax="0.5")) - float InputReleaseExpirationTimerLength = 0.0666666666666666667f; - - // Length of time within which we can recognise multiple button presses as one input. - UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, meta=(UIMin="0.02", UIMax="0.25")) - float MultiPressTimerLength = 0.025f; - - DECLARE_DELEGATE_OneParam(FNewComboInput, const class UComboInputAsset*); - FNewComboInput NewComboInput; - -private: - void AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action); - void ExpireAction(const FInputActionValue &Value, const class UInputAction *Action); - - void ActivateComboInput(const class UComboInputAsset *ComboInput); - - void ClearMultiPresses(); - void ExpireBufferedActions(); - - TObjectPtr EnhancedInputComponent; - - // Currently active combo input. - TObjectPtr InputBufferActive; - - // Combo input held until the current input has expired. - TObjectPtr InputBufferHold; - - // Set of currently locked actions; will not be activated until an unlock signal is received. - TSet> LockedComboInputs; - - TSet MostRecentActions; - TSet ExpiringActions; - - FTimerHandle MultiPressTimerHandle; - FTimerHandle InputReleaseExpirationTimerHandle; - FTimerHandle ForceUnlockTimerHandle; -}; diff --git a/Source/ComboInput/Public/GlobalSettings/InputBufferSubsystemGlobalSettings.h b/Source/ComboInput/Public/GlobalSettings/InputBufferSubsystemGlobalSettings.h new file mode 100644 index 0000000..9078d5c --- /dev/null +++ b/Source/ComboInput/Public/GlobalSettings/InputBufferSubsystemGlobalSettings.h @@ -0,0 +1,32 @@ +// ©2023 Batty Bovine Productions, LLC. All Rights Reserved. + +#pragma once + +#include "Engine/DeveloperSettingsBackedByCVars.h" + +#include "InputBufferSubsystemGlobalSettings.generated.h" + + +/** + * Global settings for the input buffer subsystem + */ +UCLASS(Config=Game, defaultconfig, meta=(DisplayName="Input Buffer Subsystem")) +class COMBOINPUT_API UInputBufferSubsystemGlobalSettings : public UDeveloperSettingsBackedByCVars +{ + GENERATED_BODY() + +public: + // List of possible combo inputs that can be taken. A combo input is selected from this list + // either if an action is made while the current combo is inactive, or when the previous + // action expires. + UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly) + TSet> ComboActions; + + // Length of time after releasing an input to keep the associated combo action buffered before clearing it. + UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly, meta = (UIMin = "0.0", UIMax = "0.5")) + float InputReleaseExpirationTimerLength = 0.0666666666666666667f; + + // Length of time within which we can recognise multiple button presses as one input. + UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly, meta = (UIMin = "0.02", UIMax = "0.25")) + float MultiPressTimerLength = 0.025f; +}; diff --git a/Source/ComboInput/Public/InputBufferLocalPlayerSubsystem.h b/Source/ComboInput/Public/InputBufferLocalPlayerSubsystem.h new file mode 100644 index 0000000000000000000000000000000000000000..2632be5f69b58ee7bbaa3fe7cb3b1177ea09e2aa GIT binary patch literal 3954 zcmd6q-EJE<5QXPf0s0P$1V|kth>KjNK>$^BZr#O4k2gyJD9jhIteFCeSK%po=}>C?PN;rrs84puH%LAHe8Ev+#& zXLii*JJ8*6&*;12nQb-M%ky6`{}(QKw-2(CRfcdiY-) z&pPF37pK``%?1+&18tKVjQ@VerEGblBYYtXYnP~ z9CK~KjTrHKwuw!T96yBr10r;acFq`o#Jkx3ce*a@Mes)%HN^We*lf#*4rMuOXSLsFX$zfoxevf{!mLADTf|T`z9Md7NZM|PSO}5gSk2Yk zGSAm3BZqKX+I#0&Mk21_KJ~SgMIL$Us?pwyi1QY7s^3{*Nm09uAE42k`6nRp^>`6m z*YW3P{TNsfGg4Q6yT58?2D~l#MEv+4KPwXY_O>_ANl=d~b@3F-5WE;;_>Ea$W3}?ync_yd|#{E9-aDLB? z=fY->Hp^uBljG*OO}q-zIxo^L>@n)hP{FOv05_pd)x721yj<{od8YP>g84be(rNg= z^ZE^SNcdMhJ_ecU2S_ z$Y)xifGPcl(CJ6^>cE^dr4xL;@J~YAMeHvdvtd*1NImhK@}6}EYj+v>t~wBFLB`U& z_hdaL4GQ13X|*2A=_K5r`>MUrk4md~uQyvM*PNQwFV?OSeY)@bUa)^Ro$Wm@U1Fnu zYdQtJA*wn@YhRbg>AajP<@&MFUW@a?`hK73;!pPD*)0329XtMeU2o&dYjlawBi_@% literal 0 HcmV?d00001 diff --git a/Source/ComboInput/Public/Interfaces/ComboHandlerInterface.h b/Source/ComboInput/Public/Interfaces/ComboHandlerInterface.h deleted file mode 100644 index ef07ed3..0000000 --- a/Source/ComboInput/Public/Interfaces/ComboHandlerInterface.h +++ /dev/null @@ -1,32 +0,0 @@ -// ©2022 Batty Bovine Productions, LLC. All Rights Reserved. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/Interface.h" -#include "ComboHandlerInterface.generated.h" - - -// This class does not need to be modified. -UINTERFACE(MinimalAPI, meta=(Blueprintable)) -class UComboHandlerInterface : public UInterface -{ - GENERATED_BODY() -}; -/** - * Interface for anything that handles combo inputs and contains a - * UComboManagerComponent. - */ -class COMBOINPUT_API IComboHandlerInterface -{ - GENERATED_BODY() - - // Add interface functions to this class. This is the class that will be inherited to implement this interface. -public: - UFUNCTION(BlueprintCallable, BlueprintNativeEvent) - class UInputBufferComponent *GetInputBuffer() const; - virtual class UInputBufferComponent *GetInputBuffer_Implementation() const; - UFUNCTION(BlueprintCallable, BlueprintNativeEvent) - class UComboManagerComponent *GetComboManager() const; - virtual class UComboManagerComponent *GetComboManager_Implementation() const; -};