RealtimeStyleTransferRuntime/Source/LyraGame/GameFeatures/GameFeatureAction_AddInputC...

155 lines
5.5 KiB
C++
Raw Normal View History

2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "GameFeatureAction_AddInputContextMapping.h"
#include "GameFeaturesSubsystem.h"
#include "GameFeaturesSubsystemSettings.h"
#include "Components/GameFrameworkComponentManager.h"
#include "GameFramework/PlayerController.h"
#include "Engine/LocalPlayer.h"
#include "EnhancedInputSubsystems.h"
#include "InputMappingContext.h"
#include "Character/LyraHeroComponent.h"
#define LOCTEXT_NAMESPACE "GameFeatures"
//////////////////////////////////////////////////////////////////////
// UGameFeatureAction_AddInputContextMapping
void UGameFeatureAction_AddInputContextMapping::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
FPerContextData& ActiveData = ContextData.FindOrAdd(Context);
if (!ensure(ActiveData.ExtensionRequestHandles.IsEmpty()) ||
!ensure(ActiveData.ControllersAddedTo.IsEmpty()))
{
Reset(ActiveData);
}
Super::OnGameFeatureActivating(Context);
}
void UGameFeatureAction_AddInputContextMapping::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
Super::OnGameFeatureDeactivating(Context);
FPerContextData* ActiveData = ContextData.Find(Context);
if (ensure(ActiveData))
{
Reset(*ActiveData);
}
}
#if WITH_EDITOR
EDataValidationResult UGameFeatureAction_AddInputContextMapping::IsDataValid(TArray<FText>& ValidationErrors)
{
EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(ValidationErrors), EDataValidationResult::Valid);
int32 Index = 0;
for (const FInputMappingContextAndPriority& Entry : InputMappings)
{
if (Entry.InputMapping.IsNull())
{
Result = EDataValidationResult::Invalid;
ValidationErrors.Add(FText::Format(LOCTEXT("NullInputMapping", "Null InputMapping at index {0}."), Index));
}
++Index;
}
return Result;
}
#endif
void UGameFeatureAction_AddInputContextMapping::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::HandleControllerExtension, ChangeContext);
TSharedPtr<FComponentRequestHandle> ExtensionRequestHandle =
ComponentManager->AddExtensionHandler(APlayerController::StaticClass(), AddAbilitiesDelegate);
ActiveData.ExtensionRequestHandles.Add(ExtensionRequestHandle);
}
}
}
void UGameFeatureAction_AddInputContextMapping::Reset(FPerContextData& ActiveData)
{
ActiveData.ExtensionRequestHandles.Empty();
while (!ActiveData.ControllersAddedTo.IsEmpty())
{
TWeakObjectPtr<APlayerController> ControllerPtr = ActiveData.ControllersAddedTo.Top();
if (ControllerPtr.IsValid())
{
RemoveInputMapping(ControllerPtr.Get(), ActiveData);
}
else
{
ActiveData.ControllersAddedTo.Pop();
}
}
}
void UGameFeatureAction_AddInputContextMapping::HandleControllerExtension(AActor* Actor, FName EventName, FGameFeatureStateChangeContext ChangeContext)
{
APlayerController* AsController = CastChecked<APlayerController>(Actor);
FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext);
// TODO Why does this code mix and match controllers and local players? ControllersAddedTo is never modified
if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionRemoved) || (EventName == UGameFrameworkComponentManager::NAME_ReceiverRemoved))
{
RemoveInputMapping(AsController, ActiveData);
}
else if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (EventName == ULyraHeroComponent::NAME_BindInputsNow))
{
AddInputMappingForPlayer(AsController->GetLocalPlayer(), ActiveData);
}
}
void UGameFeatureAction_AddInputContextMapping::AddInputMappingForPlayer(UPlayer* Player, FPerContextData& ActiveData)
{
if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player))
{
if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
for (const FInputMappingContextAndPriority& Entry : InputMappings)
{
if (const UInputMappingContext* IMC = Entry.InputMapping.Get())
{
InputSystem->AddMappingContext(IMC, Entry.Priority);
}
}
}
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_AddInputContextMapping::RemoveInputMapping(APlayerController* PlayerController, FPerContextData& ActiveData)
{
if (ULocalPlayer* LocalPlayer = PlayerController->GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
for (const FInputMappingContextAndPriority& Entry : InputMappings)
{
if (const UInputMappingContext* IMC = Entry.InputMapping.Get())
{
InputSystem->RemoveMappingContext(IMC);
}
}
}
}
ActiveData.ControllersAddedTo.Remove(PlayerController);
}
#undef LOCTEXT_NAMESPACE