Let's talk

RSAbilityInputConfig.h

Source/RSGasHelpers/Public/RSAbilityInputConfig.h Raw Download ZIP

Click a line number to link it. Shift-click to select a range.

1// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Engine/DataAsset.h"
7#include "EnhancedInputComponent.h"
8#include "GameplayTagContainer.h"
9#include "RSAbilityInputConfig.generated.h"
10
11class UInputAction;
12
13USTRUCT(BlueprintType)
14struct FRSAbilityInputBinding
15{
16 GENERATED_BODY()
17
18 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
19 TObjectPtr<const UInputAction> InputAction = nullptr;
20
21 /** Abilities whose asset tags include this tag start on press, e.g. Ability.Dash. */
22 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input", meta = (Categories = "Ability"))
23 FGameplayTag AbilityTag;
24};
25
26/**
27 * Maps Enhanced Input actions to ability tags, so abilities are bound by tag instead of by
28 * input ID. Press activates matching abilities (or forwards the press to an active one),
29 * release forwards to WaitInputRelease. See URSAbilitySystemLibrary::PressAbilityInputByTag.
30 *
31 * In C++, from SetupPlayerInputComponent:
32 *
33 * InputConfig->BindAbilityActions(CastChecked<UEnhancedInputComponent>(PlayerInputComponent),
34 * this, &AMyCharacter::AbilityInputPressed, &AMyCharacter::AbilityInputReleased);
35 *
36 * void AMyCharacter::AbilityInputPressed(FGameplayTag Tag) { URSAbilitySystemLibrary::PressAbilityInputByTag(this, Tag); }
37 * void AMyCharacter::AbilityInputReleased(FGameplayTag Tag) { URSAbilitySystemLibrary::ReleaseAbilityInputByTag(this, Tag); }
38 *
39 * In Blueprint, call Press/Release Ability Input By Tag from the Started and Completed pins.
40 */
41UCLASS(BlueprintType, Const)
42class RSGASHELPERS_API URSAbilityInputConfig : public UDataAsset
43{
44 GENERATED_BODY()
45
46public:
47 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input", meta = (TitleProperty = "AbilityTag"))
48 TArray<FRSAbilityInputBinding> AbilityInputs;
49
50 /** The tag bound to an action, or an empty tag. */
51 UFUNCTION(BlueprintPure, Category = "RS|GAS|Input")
52 FGameplayTag FindAbilityTagForAction(const UInputAction* InputAction) const;
53
54 /**
55 * Binds every entry: Started calls Pressed(Tag), Completed and Canceled call Released(Tag).
56 * Started fires once per press, so a held key does not retrigger the ability every frame.
57 */
58 template <class UserClass, typename PressedFunc, typename ReleasedFunc>
59 void BindAbilityActions(UEnhancedInputComponent* Input, UserClass* Object, PressedFunc Pressed, ReleasedFunc Released) const
60 {
61 check(Input);
62 for (const FRSAbilityInputBinding& Binding : AbilityInputs)
63 {
64 if (!Binding.InputAction || !Binding.AbilityTag.IsValid())
65 {
66 continue;
67 }
68 Input->BindAction(Binding.InputAction, ETriggerEvent::Started, Object, Pressed, Binding.AbilityTag);
69 Input->BindAction(Binding.InputAction, ETriggerEvent::Completed, Object, Released, Binding.AbilityTag);
70 Input->BindAction(Binding.InputAction, ETriggerEvent::Canceled, Object, Released, Binding.AbilityTag);
71 }
72 }
73};

Still desyncing in packaged builds?

Free code fixes one symptom. A Diagnostic finds the cause across your project in two days.