169 lines
5.8 KiB
C++
169 lines
5.8 KiB
C++
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
||
|
#include "GameFeatureAction_AddInputBinding.h"
|
||
|
#include "GameFeaturesSubsystem.h"
|
||
|
#include "GameFeaturesSubsystemSettings.h"
|
||
|
#include "Components/GameFrameworkComponentManager.h"
|
||
|
#include "GameFramework/PlayerController.h"
|
||
|
#include "GameFramework/Pawn.h"
|
||
|
#include "EnhancedInputSubsystems.h"
|
||
|
#include "InputMappingContext.h"
|
||
|
#include "Engine/LocalPlayer.h"
|
||
|
#include "Character/LyraHeroComponent.h"
|
||
|
#include "Input/LyraInputConfig.h"
|
||
|
|
||
|
#define LOCTEXT_NAMESPACE "GameFeatures"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// UGameFeatureAction_AddInputBinding
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
|
||
|
{
|
||
|
FPerContextData& ActiveData = ContextData.FindOrAdd(Context);
|
||
|
if (!ensure(ActiveData.ExtensionRequestHandles.IsEmpty()) ||
|
||
|
!ensure(ActiveData.PawnsAddedTo.IsEmpty()))
|
||
|
{
|
||
|
Reset(ActiveData);
|
||
|
}
|
||
|
Super::OnGameFeatureActivating(Context);
|
||
|
}
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
|
||
|
{
|
||
|
Super::OnGameFeatureDeactivating(Context);
|
||
|
FPerContextData* ActiveData = ContextData.Find(Context);
|
||
|
|
||
|
if (ensure(ActiveData))
|
||
|
{
|
||
|
Reset(*ActiveData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if WITH_EDITOR
|
||
|
EDataValidationResult UGameFeatureAction_AddInputBinding::IsDataValid(TArray<FText>& ValidationErrors)
|
||
|
{
|
||
|
EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(ValidationErrors), EDataValidationResult::Valid);
|
||
|
|
||
|
int32 Index = 0;
|
||
|
|
||
|
for (const TSoftObjectPtr<const ULyraInputConfig>& Entry : InputConfigs)
|
||
|
{
|
||
|
if (Entry.IsNull())
|
||
|
{
|
||
|
Result = EDataValidationResult::Invalid;
|
||
|
ValidationErrors.Add(FText::Format(LOCTEXT("NullInputConfig", "Null InputConfig at index {0}."), Index));
|
||
|
}
|
||
|
++Index;
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::AddToWorld(const FWorldContext& WorldContext, const FGameFeatureStateChangeContext& ChangeContext)
|
||
|
{
|
||
|
UWorld* World = WorldContext.World();
|
||
|
UGameInstance* GameInstance = WorldContext.OwningGameInstance;
|
||
|
FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext);
|
||
|
|
||
|
if ((GameInstance != nullptr) && (World != nullptr) && World->IsGameWorld())
|
||
|
{
|
||
|
if (UGameFrameworkComponentManager* ComponentManager = UGameInstance::GetSubsystem<UGameFrameworkComponentManager>(GameInstance))
|
||
|
{
|
||
|
UGameFrameworkComponentManager::FExtensionHandlerDelegate AddAbilitiesDelegate =
|
||
|
UGameFrameworkComponentManager::FExtensionHandlerDelegate::CreateUObject(this, &ThisClass::HandlePawnExtension, ChangeContext);
|
||
|
TSharedPtr<FComponentRequestHandle> ExtensionRequestHandle =
|
||
|
ComponentManager->AddExtensionHandler(APawn::StaticClass(), AddAbilitiesDelegate);
|
||
|
|
||
|
ActiveData.ExtensionRequestHandles.Add(ExtensionRequestHandle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::Reset(FPerContextData& ActiveData)
|
||
|
{
|
||
|
ActiveData.ExtensionRequestHandles.Empty();
|
||
|
|
||
|
while (!ActiveData.PawnsAddedTo.IsEmpty())
|
||
|
{
|
||
|
TWeakObjectPtr<APawn> PawnPtr = ActiveData.PawnsAddedTo.Top();
|
||
|
if (PawnPtr.IsValid())
|
||
|
{
|
||
|
RemoveInputMapping(PawnPtr.Get(), ActiveData);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ActiveData.PawnsAddedTo.Pop();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::HandlePawnExtension(AActor* Actor, FName EventName, FGameFeatureStateChangeContext ChangeContext)
|
||
|
{
|
||
|
APawn* AsPawn = CastChecked<APawn>(Actor);
|
||
|
FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext);
|
||
|
|
||
|
if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionRemoved) || (EventName == UGameFrameworkComponentManager::NAME_ReceiverRemoved))
|
||
|
{
|
||
|
RemoveInputMapping(AsPawn, ActiveData);
|
||
|
}
|
||
|
else if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (EventName == ULyraHeroComponent::NAME_BindInputsNow))
|
||
|
{
|
||
|
AddInputMappingForPlayer(AsPawn, ActiveData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::AddInputMappingForPlayer(APawn* Pawn, FPerContextData& ActiveData)
|
||
|
{
|
||
|
APlayerController* PlayerController = Cast<APlayerController>(Pawn->GetController());
|
||
|
|
||
|
if (ULocalPlayer* LocalPlayer = PlayerController ? PlayerController->GetLocalPlayer() : nullptr)
|
||
|
{
|
||
|
if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
|
||
|
{
|
||
|
ULyraHeroComponent* HeroComponent = Pawn->FindComponentByClass<ULyraHeroComponent>();
|
||
|
if (HeroComponent && HeroComponent->IsReadyToBindInputs())
|
||
|
{
|
||
|
for (const TSoftObjectPtr<const ULyraInputConfig>& Entry : InputConfigs)
|
||
|
{
|
||
|
if (const ULyraInputConfig* BindSet = Entry.Get())
|
||
|
{
|
||
|
HeroComponent->AddAdditionalInputConfig(BindSet);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
ActiveData.PawnsAddedTo.AddUnique(Pawn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogGameFeatures, Error, TEXT("Failed to find `UEnhancedInputLocalPlayerSubsystem` for local player. Input mappings will not be added. Make sure you're set to use the EnhancedInput system via config file."));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UGameFeatureAction_AddInputBinding::RemoveInputMapping(APawn* Pawn, FPerContextData& ActiveData)
|
||
|
{
|
||
|
APlayerController* PlayerController = Cast<APlayerController>(Pawn->GetController());
|
||
|
|
||
|
if (ULocalPlayer* LocalPlayer = PlayerController ? PlayerController->GetLocalPlayer() : nullptr)
|
||
|
{
|
||
|
if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
|
||
|
{
|
||
|
if (ULyraHeroComponent* HeroComponent = Pawn->FindComponentByClass<ULyraHeroComponent>())
|
||
|
{
|
||
|
for (const TSoftObjectPtr<const ULyraInputConfig>& Entry : InputConfigs)
|
||
|
{
|
||
|
if (const ULyraInputConfig* InputConfig = Entry.Get())
|
||
|
{
|
||
|
HeroComponent->RemoveAdditionalInputConfig(InputConfig);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ActiveData.PawnsAddedTo.Remove(Pawn);
|
||
|
}
|
||
|
|
||
|
#undef LOCTEXT_NAMESPACE
|