Added GameFeatureActions, HeroComponent, and AbilityCost.
This commit is contained in:
parent
51306c57a9
commit
2c4a71b343
@ -0,0 +1,28 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
|
||||||
|
#include "AbilitySystem/Abilities/OLSAbilityCost.h"
|
||||||
|
|
||||||
|
UOLSAbilityCost::UOLSAbilityCost()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UOLSAbilityCost::CheckCost(const UOLSGameplayAbility* ability,
|
||||||
|
const FGameplayAbilitySpecHandle handle,
|
||||||
|
const FGameplayAbilityActorInfo* actorInfo,
|
||||||
|
FGameplayTagContainer* optionalRelevantTags) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSAbilityCost::ApplyCost(const UOLSGameplayAbility* ability,
|
||||||
|
const FGameplayAbilitySpecHandle handle,
|
||||||
|
const FGameplayAbilityActorInfo* actorInfo,
|
||||||
|
const FGameplayAbilityActivationInfo activationInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UOLSAbilityCost::ShouldOnlyApplyCostOnHit() const
|
||||||
|
{
|
||||||
|
return bShouldOnlyApplyCostOnHit;
|
||||||
|
}
|
@ -695,7 +695,7 @@ void UOLSAbilitySystemComponent::RemoveDynamicTagGameplayEffect(const FGameplayT
|
|||||||
{
|
{
|
||||||
OLS_LOG(LogOLSAbilitySystemComponent, Warning,
|
OLS_LOG(LogOLSAbilitySystemComponent, Warning,
|
||||||
TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."),
|
TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."),
|
||||||
UOLSGameDataAsset::Get().DynamicTagGameplayEffect.GetAssetName());
|
*UOLSGameDataAsset::Get().DynamicTagGameplayEffect.GetAssetName());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
517
Source/ols/Private/Components/OLSHeroComponent.cpp
Normal file
517
Source/ols/Private/Components/OLSHeroComponent.cpp
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
|
||||||
|
#include "Components/OLSHeroComponent.h"
|
||||||
|
|
||||||
|
#include "EnhancedInputSubsystems.h"
|
||||||
|
#include "OLSLog.h"
|
||||||
|
#include "AbilitySystem/OLSAbilitySystemComponent.h"
|
||||||
|
#include "Characters/OLSCharacter.h"
|
||||||
|
#include "Components/GameFrameworkComponentManager.h"
|
||||||
|
#include "Components/OLSPawnExtensionComponent.h"
|
||||||
|
#include "DataAssets/OLSPawnDataAsset.h"
|
||||||
|
#include "GameFeatures/OLSGameFeatureAction_AddInputContextMapping.h"
|
||||||
|
#include "Player/OLSPlayerController.h"
|
||||||
|
#include "Player/OLSPlayerState.h"
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
#include "Misc/UObjectToken.h"
|
||||||
|
#endif // WITH_EDITOR
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY(LogOLSHeroComponent);
|
||||||
|
|
||||||
|
namespace OLSHero
|
||||||
|
{
|
||||||
|
static const float LookYawRate = 300.0f;
|
||||||
|
static const float LookPitchRate = 165.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FName UOLSHeroComponent::NAME_BindInputsNow("BindInputsNow");
|
||||||
|
const FName UOLSHeroComponent::NAME_ActorFeatureName("Hero");
|
||||||
|
|
||||||
|
UOLSHeroComponent::UOLSHeroComponent(const FObjectInitializer& objectInitializer) : Super(objectInitializer)
|
||||||
|
{
|
||||||
|
//@TODO: implement UOLSCameraMode.
|
||||||
|
// AbilityCameraMode = nullptr;
|
||||||
|
bIsReadyToBindInputs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FName UOLSHeroComponent::GetFeatureName() const
|
||||||
|
{
|
||||||
|
// Don't call Super since it does not fit in this.
|
||||||
|
|
||||||
|
return NAME_ActorFeatureName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UOLSHeroComponent::CanChangeInitState(UGameFrameworkComponentManager* manager,
|
||||||
|
FGameplayTag currentState,
|
||||||
|
FGameplayTag desiredState) const
|
||||||
|
{
|
||||||
|
// Don't call Super since it does not fit into this.
|
||||||
|
|
||||||
|
check(manager);
|
||||||
|
|
||||||
|
APawn* pawn = GetPawn<APawn>();
|
||||||
|
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_Spawned.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_DataAvailable.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_DataInitialized.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_GameplayReady.
|
||||||
|
// if (!currentState.IsValid() && desiredState == LyraGameplayTags::InitState_Spawned)
|
||||||
|
// {
|
||||||
|
// // As long as we have a real pawn, let us transition
|
||||||
|
// if (pawn)
|
||||||
|
// {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if (currentState == LyraGameplayTags::InitState_Spawned && desiredState == LyraGameplayTags::InitState_DataAvailable)
|
||||||
|
// {
|
||||||
|
// // The player state is required.
|
||||||
|
// if (!GetPlayerState<AOLSPlayerState>())
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // If we're authority or autonomous, we need to wait for a controller with registered ownership of the player state.
|
||||||
|
// if (pawn->GetLocalRole() != ROLE_SimulatedProxy)
|
||||||
|
// {
|
||||||
|
// AController* controller = GetController<AController>();
|
||||||
|
//
|
||||||
|
// const bool hasControllerPairedWithPS = (controller != nullptr) && \
|
||||||
|
// (controller->PlayerState != nullptr) && \
|
||||||
|
// (controller->PlayerState->GetOwner() == controller);
|
||||||
|
//
|
||||||
|
// if (!hasControllerPairedWithPS)
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const bool isLocallyControlled = pawn->IsLocallyControlled();
|
||||||
|
// const bool isBot = pawn->IsBotControlled();
|
||||||
|
//
|
||||||
|
// if (isLocallyControlled && !isBot)
|
||||||
|
// {
|
||||||
|
// AOLSPlayerController* playerController = GetController<AOLSPlayerController>();
|
||||||
|
//
|
||||||
|
// // The input component and local player is required when locally controlled.
|
||||||
|
// if (!pawn->InputComponent || !playerController || !playerController->GetLocalPlayer())
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// else if (currentState == LyraGameplayTags::InitState_DataAvailable && desiredState == LyraGameplayTags::InitState_DataInitialized)
|
||||||
|
// {
|
||||||
|
// // Wait for player state and extension component
|
||||||
|
// AOLSPlayerState* playerState = GetPlayerState<AOLSPlayerState>();
|
||||||
|
//
|
||||||
|
// return playerState && manager->HasFeatureReachedInitState(pawn, UOLSPawnExtensionComponent::NAME_ActorFeatureName, LyraGameplayTags::InitState_DataInitialized);
|
||||||
|
// }
|
||||||
|
// else if (currentState == LyraGameplayTags::InitState_DataInitialized && desiredState == LyraGameplayTags::InitState_GameplayReady)
|
||||||
|
// {
|
||||||
|
// // TODO add ability initialization checks?
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::HandleChangeInitState(UGameFrameworkComponentManager* manager,
|
||||||
|
FGameplayTag currentState,
|
||||||
|
FGameplayTag desiredState)
|
||||||
|
{
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_DataAvailable.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_DataInitialized.
|
||||||
|
// if (currentState == LyraGameplayTags::InitState_DataAvailable && desiredState == LyraGameplayTags::InitState_DataInitialized)
|
||||||
|
// {
|
||||||
|
// APawn* pawn = GetPawn<APawn>();
|
||||||
|
// AOLSPlayerState* playerState = GetPlayerState<AOLSPlayerState>();
|
||||||
|
// if (!ensure(pawn && playerState))
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const UOLSPawnDataAsset* pawnData = nullptr;
|
||||||
|
//
|
||||||
|
// if (UOLSPawnExtensionComponent* PawnExtComp = UOLSPawnExtensionComponent::FindPawnExtensionComponent(pawn))
|
||||||
|
// {
|
||||||
|
// pawnData = PawnExtComp->GetPawnData<UOLSPawnDataAsset>();
|
||||||
|
//
|
||||||
|
// // The player state holds the persistent data for this player (state that persists across deaths and multiple pawns).
|
||||||
|
// // The ability system component and attribute sets live on the player state.
|
||||||
|
// PawnExtComp->InitializeAbilitySystem(playerState->GetOLSAbilitySystemComponent(), playerState);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (AOLSPlayerController* playerController = GetController<AOLSPlayerController>())
|
||||||
|
// {
|
||||||
|
// if (pawn->InputComponent)
|
||||||
|
// {
|
||||||
|
// InitializePlayerInput(pawn->InputComponent);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// //@TODO: implement UOLSCameraMode.
|
||||||
|
// // Hook up the delegate for all pawns, in case we spectate later
|
||||||
|
// // if (pawnData)
|
||||||
|
// // {
|
||||||
|
// // if (ULyraCameraComponent* CameraComponent = ULyraCameraComponent::FindCameraComponent(pawn))
|
||||||
|
// // {
|
||||||
|
// // CameraComponent->DetermineCameraModeDelegate.BindUObject(this, &ThisClass::DetermineCameraMode);
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::OnActorInitStateChanged(const FActorInitStateChangedParams& params)
|
||||||
|
{
|
||||||
|
// if (params.FeatureName == UOLSPawnExtensionComponent::NAME_ActorFeatureName)
|
||||||
|
// {
|
||||||
|
// //@TODO: implement LyraGameplayTags::InitState_DataAvailable.
|
||||||
|
// if (params.FeatureState == LyraGameplayTags::InitState_DataInitialized)
|
||||||
|
// {
|
||||||
|
// // If the extension component says all other components are initialized, try to progress to next state
|
||||||
|
// CheckDefaultInitialization();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::CheckDefaultInitialization()
|
||||||
|
{
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_Spawned.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_DataAvailable.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_DataInitialized.
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_GameplayReady.
|
||||||
|
// static const TArray<FGameplayTag> stateChain = {
|
||||||
|
// LyraGameplayTags::InitState_Spawned, LyraGameplayTags::InitState_DataAvailable,
|
||||||
|
// LyraGameplayTags::InitState_DataInitialized, LyraGameplayTags::InitState_GameplayReady
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// // This will try to progress from spawned (which is only set in BeginPlay) through the data initialization stages until it gets to gameplay ready
|
||||||
|
// ContinueInitStateChain(stateChain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& owningSpecHandle)
|
||||||
|
{
|
||||||
|
if (AbilityCameraModeOwningSpecHandle == owningSpecHandle)
|
||||||
|
{
|
||||||
|
//@TODO: implement UOLSCameraMode.
|
||||||
|
// AbilityCameraMode = nullptr;
|
||||||
|
AbilityCameraModeOwningSpecHandle = FGameplayAbilitySpecHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::AddAdditionalInputConfig(const UOLSInputConfigDataAsset* inputConfig)
|
||||||
|
{
|
||||||
|
TArray<uint32> bindHandles;
|
||||||
|
|
||||||
|
const APawn* pawn = GetPawn<APawn>();
|
||||||
|
if (!pawn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const APlayerController* playerController = GetController<APlayerController>();
|
||||||
|
check(playerController);
|
||||||
|
|
||||||
|
const ULocalPlayer* localPlayer = playerController->GetLocalPlayer();
|
||||||
|
check(localPlayer);
|
||||||
|
|
||||||
|
UEnhancedInputLocalPlayerSubsystem* subsystem = localPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
|
||||||
|
check(subsystem);
|
||||||
|
|
||||||
|
if (const UOLSPawnExtensionComponent* pawnExtComp = UOLSPawnExtensionComponent::FindPawnExtensionComponent(pawn))
|
||||||
|
{
|
||||||
|
//@TODO: Implement UOLSInputComponent.
|
||||||
|
// UOLSInputComponent* inputComponent = pawn->FindComponentByClass<UOLSInputComponent>();
|
||||||
|
// if (ensureMsgf(inputComponent,
|
||||||
|
// TEXT(
|
||||||
|
// "Unexpected Input Component class! The Gameplay Abilities will not be bound to their inputs. Change the input component to ULyraInputComponent or a subclass of it."
|
||||||
|
// )))
|
||||||
|
// {
|
||||||
|
// inputComponent->BindAbilityActions(inputConfig, this, &ThisClass::Input_AbilityInputTagPressed,
|
||||||
|
// &ThisClass::Input_AbilityInputTagReleased, /*out*/ bindHandles);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::RemoveAdditionalInputConfig(const UOLSInputConfigDataAsset* inputConfig)
|
||||||
|
{
|
||||||
|
//@TODO: Implement me!
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UOLSHeroComponent::IsReadyToBindInputs() const
|
||||||
|
{
|
||||||
|
return bIsReadyToBindInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::OnRegister()
|
||||||
|
{
|
||||||
|
Super::OnRegister();
|
||||||
|
|
||||||
|
if (!GetPawn<APawn>())
|
||||||
|
{
|
||||||
|
OLS_LOG(LogOLSHeroComponent, Error,
|
||||||
|
TEXT(
|
||||||
|
"This component has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint."
|
||||||
|
));
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
if (GIsEditor)
|
||||||
|
{
|
||||||
|
static const FText message = NSLOCTEXT("OLSHeroComponent", "NotOnPawnError",
|
||||||
|
"has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint. This will cause a crash if you PIE!");
|
||||||
|
static const FName heroMessageLogName = TEXT("OLSHeroComponent");
|
||||||
|
|
||||||
|
FMessageLog(heroMessageLogName).Error()
|
||||||
|
->AddToken(FUObjectToken::Create(this, FText::FromString(GetNameSafe(this))))
|
||||||
|
->AddToken(FTextToken::Create(message));
|
||||||
|
|
||||||
|
FMessageLog(heroMessageLogName).Open();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Register with the init state system early, this will only work if this is a game world
|
||||||
|
RegisterInitStateFeature();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::BeginPlay()
|
||||||
|
{
|
||||||
|
Super::BeginPlay();
|
||||||
|
|
||||||
|
// Listen for when the pawn extension component changes init state
|
||||||
|
BindOnActorInitStateChanged(UOLSPawnExtensionComponent::NAME_ActorFeatureName, FGameplayTag(), false);
|
||||||
|
|
||||||
|
// Notifies that we are done spawning, then try the rest of initialization
|
||||||
|
//@TODO: implement LyraGameplayTags::InitState_Spawned.
|
||||||
|
// ensure(TryToChangeInitState(LyraGameplayTags::InitState_Spawned));
|
||||||
|
CheckDefaultInitialization();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::EndPlay(const EEndPlayReason::Type endPlayReason)
|
||||||
|
{
|
||||||
|
UnregisterInitStateFeature();
|
||||||
|
|
||||||
|
Super::EndPlay(endPlayReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::InitializePlayerInput(UInputComponent* playerInputComponent)
|
||||||
|
{
|
||||||
|
check(playerInputComponent);
|
||||||
|
|
||||||
|
const APawn* Pawn = GetPawn<APawn>();
|
||||||
|
if (!Pawn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const APlayerController* playerController = GetController<APlayerController>();
|
||||||
|
check(playerController);
|
||||||
|
|
||||||
|
//@TODO implement UOLSLocalPlayer.
|
||||||
|
// const UOLSLocalPlayer* localPlayer = Cast<UOLSLocalPlayer>(playerController->GetLocalPlayer());
|
||||||
|
// check(localPlayer);
|
||||||
|
|
||||||
|
// UEnhancedInputLocalPlayerSubsystem* subsystem = localPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
|
||||||
|
// check(subsystem);
|
||||||
|
//
|
||||||
|
// subsystem->ClearAllMappings();
|
||||||
|
|
||||||
|
// if (const UOLSPawnExtensionComponent* pawnExtComp = UOLSPawnExtensionComponent::FindPawnExtensionComponent(Pawn))
|
||||||
|
// {
|
||||||
|
// if (const UOLSPawnDataAsset* pawnData = pawnExtComp->GetPawnData<UOLSPawnDataAsset>())
|
||||||
|
// {
|
||||||
|
// //@TODO: Implement UOLSInputConfig
|
||||||
|
// if (const UOLSInputConfig* inputConfig = pawnData->InputConfig)
|
||||||
|
// {
|
||||||
|
// for (const FOLSInputMappingContextAndPriority& mapping : DefaultInputMappings)
|
||||||
|
// {
|
||||||
|
// if (UInputMappingContext* imc = mapping.InputMapping.Get())
|
||||||
|
// {
|
||||||
|
// if (mapping.bShouldRegisterWithSettings)
|
||||||
|
// {
|
||||||
|
// if (UEnhancedInputUserSettings* settings = subsystem->GetUserSettings())
|
||||||
|
// {
|
||||||
|
// settings->RegisterInputMappingContext(imc);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// FModifyContextOptions options = {};
|
||||||
|
// options.bIgnoreAllPressedKeysUntilRelease = false;
|
||||||
|
// // Actually add the config to the local player
|
||||||
|
// subsystem->AddMappingContext(imc, mapping.Priority, options);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // The Lyra Input Component has some additional functions to map Gameplay Tags to an Input Action.
|
||||||
|
// // If you want this functionality but still want to change your input component class, make it a subclass
|
||||||
|
// // of the ULyraInputComponent or modify this component accordingly.
|
||||||
|
// //@TODO: Implement UOLSInputComponent.
|
||||||
|
// // UOLSInputComponent* inputComponent = Cast<UOLSInputComponent>(playerInputComponent);
|
||||||
|
// if (ensureMsgf(inputComponent,
|
||||||
|
// TEXT(
|
||||||
|
// "Unexpected Input Component class! The Gameplay Abilities will not be bound to their inputs. Change the input component to ULyraInputComponent or a subclass of it."
|
||||||
|
// )))
|
||||||
|
// {
|
||||||
|
// // Add the key mappings that may have been set by the player
|
||||||
|
// inputComponent->AddInputMappings(inputConfig, subsystem);
|
||||||
|
//
|
||||||
|
// // This is where we actually bind and input action to a gameplay tag, which means that Gameplay Ability Blueprints will
|
||||||
|
// // be triggered directly by these input actions Triggered events.
|
||||||
|
// TArray<uint32> BindHandles;
|
||||||
|
// inputComponent->BindAbilityActions(inputConfig, this, &ThisClass::Input_AbilityInputTagPressed, &ThisClass::Input_AbilityInputTagReleased, /*out*/ BindHandles);
|
||||||
|
//
|
||||||
|
// inputComponent->BindNativeAction(inputConfig, LyraGameplayTags::InputTag_Move, ETriggerEvent::Triggered, this, &ThisClass::Input_Move, /*bLogIfNotFound=*/ false);
|
||||||
|
// inputComponent->BindNativeAction(inputConfig, LyraGameplayTags::InputTag_Look_Mouse, ETriggerEvent::Triggered, this, &ThisClass::Input_LookMouse, /*bLogIfNotFound=*/ false);
|
||||||
|
// inputComponent->BindNativeAction(inputConfig, LyraGameplayTags::InputTag_Look_Stick, ETriggerEvent::Triggered, this, &ThisClass::Input_LookStick, /*bLogIfNotFound=*/ false);
|
||||||
|
// inputComponent->BindNativeAction(inputConfig, LyraGameplayTags::InputTag_Crouch, ETriggerEvent::Triggered, this, &ThisClass::Input_Crouch, /*bLogIfNotFound=*/ false);
|
||||||
|
// inputComponent->BindNativeAction(inputConfig, LyraGameplayTags::InputTag_AutoRun, ETriggerEvent::Triggered, this, &ThisClass::Input_AutoRun, /*bLogIfNotFound=*/ false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (ensure(!bIsReadyToBindInputs))
|
||||||
|
{
|
||||||
|
bIsReadyToBindInputs = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast<APlayerController*>(playerController), NAME_BindInputsNow);
|
||||||
|
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast<APawn*>(Pawn), NAME_BindInputsNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_AbilityInputTagPressed(FGameplayTag inputTag)
|
||||||
|
{
|
||||||
|
if (const APawn* pawn = GetPawn<APawn>())
|
||||||
|
{
|
||||||
|
if (const UOLSPawnExtensionComponent* pawnExtComp = UOLSPawnExtensionComponent::FindPawnExtensionComponent(pawn))
|
||||||
|
{
|
||||||
|
if (UOLSAbilitySystemComponent* asc = pawnExtComp->GetOLSAbilitySystemComponent())
|
||||||
|
{
|
||||||
|
asc->AbilityInputTagPressed(inputTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_AbilityInputTagReleased(FGameplayTag inputTag)
|
||||||
|
{
|
||||||
|
const APawn* pawn = GetPawn<APawn>();
|
||||||
|
if (!pawn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const UOLSPawnExtensionComponent* pawnExtComp = UOLSPawnExtensionComponent::FindPawnExtensionComponent(pawn))
|
||||||
|
{
|
||||||
|
if (UOLSAbilitySystemComponent* asc = pawnExtComp->GetOLSAbilitySystemComponent())
|
||||||
|
{
|
||||||
|
asc->AbilityInputTagReleased(inputTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_Move(const FInputActionValue& inputActionValue)
|
||||||
|
{
|
||||||
|
APawn* pawn = GetPawn<APawn>();
|
||||||
|
AController* controller = pawn ? pawn->GetController() : nullptr;
|
||||||
|
|
||||||
|
// If the player has attempted to move again then cancel auto running
|
||||||
|
if (AOLSPlayerController* playerController = Cast<AOLSPlayerController>(controller))
|
||||||
|
{
|
||||||
|
//@TODO: Should we have this?
|
||||||
|
// playerController->SetIsAutoRunning(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller)
|
||||||
|
{
|
||||||
|
const FVector2D value = inputActionValue.Get<FVector2D>();
|
||||||
|
const FRotator movementRotation(0.0f, controller->GetControlRotation().Yaw, 0.0f);
|
||||||
|
|
||||||
|
if (value.X != 0.0f)
|
||||||
|
{
|
||||||
|
const FVector movementDirection = movementRotation.RotateVector(FVector::RightVector);
|
||||||
|
pawn->AddMovementInput(movementDirection, value.X);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Y != 0.0f)
|
||||||
|
{
|
||||||
|
const FVector movementDirection = movementRotation.RotateVector(FVector::ForwardVector);
|
||||||
|
pawn->AddMovementInput(movementDirection, value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_LookMouse(const FInputActionValue& inputActionValue)
|
||||||
|
{
|
||||||
|
APawn* pawn = GetPawn<APawn>();
|
||||||
|
|
||||||
|
if (!pawn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FVector2D value = inputActionValue.Get<FVector2D>();
|
||||||
|
|
||||||
|
if (value.X != 0.0f)
|
||||||
|
{
|
||||||
|
pawn->AddControllerYawInput(value.X);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Y != 0.0f)
|
||||||
|
{
|
||||||
|
pawn->AddControllerPitchInput(value.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_LookStick(const FInputActionValue& inputActionValue)
|
||||||
|
{
|
||||||
|
APawn* pawn = GetPawn<APawn>();
|
||||||
|
|
||||||
|
if (!pawn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FVector2D value = inputActionValue.Get<FVector2D>();
|
||||||
|
|
||||||
|
const UWorld* world = GetWorld();
|
||||||
|
check(world);
|
||||||
|
|
||||||
|
if (value.X != 0.0f)
|
||||||
|
{
|
||||||
|
pawn->AddControllerYawInput(value.X * OLSHero::LookYawRate * world->GetDeltaSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.Y != 0.0f)
|
||||||
|
{
|
||||||
|
pawn->AddControllerPitchInput(value.Y * OLSHero::LookPitchRate * world->GetDeltaSeconds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_Crouch(const FInputActionValue& inputActionValue)
|
||||||
|
{
|
||||||
|
if (AOLSCharacter* character = GetPawn<AOLSCharacter>())
|
||||||
|
{
|
||||||
|
character->ToggleCrouch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSHeroComponent::Input_AutoRun(const FInputActionValue& inputActionValue)
|
||||||
|
{
|
||||||
|
if (APawn* Pawp = GetPawn<APawn>())
|
||||||
|
{
|
||||||
|
if (AOLSPlayerController* controller = Cast<AOLSPlayerController>(Pawp->GetController()))
|
||||||
|
{
|
||||||
|
//@TODO: Should we have this?
|
||||||
|
// Toggle auto running
|
||||||
|
// controller->SetIsAutoRunning(!controller->GetIsAutoRunning());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,9 +7,12 @@
|
|||||||
#include "AbilitySystem/OLSAbilitySystemComponent.h"
|
#include "AbilitySystem/OLSAbilitySystemComponent.h"
|
||||||
#include "Components/GameFrameworkComponentManager.h"
|
#include "Components/GameFrameworkComponentManager.h"
|
||||||
#include "DataAssets/OLSPawnDataAsset.h"
|
#include "DataAssets/OLSPawnDataAsset.h"
|
||||||
|
#include "Net/UnrealNetwork.h"
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(LogOLSPawnExtensionComponent);
|
DEFINE_LOG_CATEGORY(LogOLSPawnExtensionComponent);
|
||||||
|
|
||||||
|
const FName UOLSPawnExtensionComponent::NAME_ActorFeatureName("PawnExtension");
|
||||||
|
|
||||||
UOLSPawnExtensionComponent::UOLSPawnExtensionComponent(const FObjectInitializer& objectInitializer)
|
UOLSPawnExtensionComponent::UOLSPawnExtensionComponent(const FObjectInitializer& objectInitializer)
|
||||||
: Super(objectInitializer)
|
: Super(objectInitializer)
|
||||||
{
|
{
|
||||||
@ -22,6 +25,13 @@ UOLSPawnExtensionComponent::UOLSPawnExtensionComponent(const FObjectInitializer&
|
|||||||
AbilitySystemComponent = nullptr;
|
AbilitySystemComponent = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UOLSPawnExtensionComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||||
|
{
|
||||||
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||||
|
|
||||||
|
DOREPLIFETIME(UOLSPawnExtensionComponent, PawnData);
|
||||||
|
}
|
||||||
|
|
||||||
FName UOLSPawnExtensionComponent::GetFeatureName() const
|
FName UOLSPawnExtensionComponent::GetFeatureName() const
|
||||||
{
|
{
|
||||||
return NAME_ActorFeatureName;
|
return NAME_ActorFeatureName;
|
||||||
|
@ -0,0 +1,308 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
|
||||||
|
#include "GameFeatures/OLSGameFeatureAction_AddInputContextMapping.h"
|
||||||
|
|
||||||
|
#include "UserSettings/EnhancedInputUserSettings.h"
|
||||||
|
#include "EnhancedInputSubsystems.h"
|
||||||
|
#include "Systems/OLSAssetManager.h"
|
||||||
|
#include "Engine/LocalPlayer.h"
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
#include "Misc/DataValidation.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "InputMappingContext.h"
|
||||||
|
#include "OLSLog.h"
|
||||||
|
#include "Components/GameFrameworkComponentManager.h"
|
||||||
|
#include "Components/OLSHeroComponent.h"
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY(LogOLSGameFA_AddInputContextMapping);
|
||||||
|
|
||||||
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(OLSGameFeatureAction_AddInputContextMapping)
|
||||||
|
|
||||||
|
#define LOCTEXT_NAMESPACE "GameFeatures"
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::OnGameFeatureRegistering()
|
||||||
|
{
|
||||||
|
Super::OnGameFeatureRegistering();
|
||||||
|
|
||||||
|
RegisterInputMappingContexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::OnGameFeatureActivating(FGameFeatureActivatingContext& context)
|
||||||
|
{
|
||||||
|
FPerContextData& activeData = ContextData.FindOrAdd(context);
|
||||||
|
if (!ensure(activeData.ExtensionRequestHandles.IsEmpty()) ||
|
||||||
|
!ensure(activeData.ControllersAddedTo.IsEmpty()))
|
||||||
|
{
|
||||||
|
Reset(activeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Super::OnGameFeatureActivating(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& context)
|
||||||
|
{
|
||||||
|
Super::OnGameFeatureDeactivating(context);
|
||||||
|
|
||||||
|
FPerContextData* activeData = ContextData.Find(context);
|
||||||
|
if (ensure(activeData))
|
||||||
|
{
|
||||||
|
Reset(*activeData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::OnGameFeatureUnregistering()
|
||||||
|
{
|
||||||
|
Super::OnGameFeatureUnregistering();
|
||||||
|
|
||||||
|
UnregisterInputMappingContexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
EDataValidationResult UOLSGameFeatureAction_AddInputContextMapping::IsDataValid(FDataValidationContext& context) const
|
||||||
|
{
|
||||||
|
// Don't call Super since it does not fit in this.
|
||||||
|
|
||||||
|
EDataValidationResult result = CombineDataValidationResults(Super::IsDataValid(context), EDataValidationResult::Valid);
|
||||||
|
|
||||||
|
int32 index = 0;
|
||||||
|
|
||||||
|
for (const FOLSInputMappingContextAndPriority& entry : InputMappings)
|
||||||
|
{
|
||||||
|
if (entry.InputMapping.IsNull())
|
||||||
|
{
|
||||||
|
result = EDataValidationResult::Invalid;
|
||||||
|
context.AddError(FText::Format(LOCTEXT("NullInputMapping", "Null InputMapping at index {0}."), index));
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::RegisterInputMappingContexts()
|
||||||
|
{
|
||||||
|
RegisterInputContextMappingsForGameInstanceHandle = FWorldDelegates::OnStartGameInstance.AddUObject(
|
||||||
|
this, &UOLSGameFeatureAction_AddInputContextMapping::RegisterInputContextMappingsForGameInstance);
|
||||||
|
|
||||||
|
const TIndirectArray<FWorldContext>& worldContexts = GEngine->GetWorldContexts();
|
||||||
|
for (TIndirectArray<FWorldContext>::TConstIterator worldContextIterator = worldContexts.CreateConstIterator();
|
||||||
|
worldContextIterator; ++worldContextIterator)
|
||||||
|
{
|
||||||
|
RegisterInputContextMappingsForGameInstance(worldContextIterator->OwningGameInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::RegisterInputContextMappingsForGameInstance(
|
||||||
|
UGameInstance* gameInstance)
|
||||||
|
{
|
||||||
|
if (gameInstance != nullptr && !gameInstance->OnLocalPlayerAddedEvent.IsBoundToObject(this))
|
||||||
|
{
|
||||||
|
gameInstance->OnLocalPlayerAddedEvent.AddUObject(
|
||||||
|
this, &UOLSGameFeatureAction_AddInputContextMapping::RegisterInputMappingContextsForLocalPlayer);
|
||||||
|
gameInstance->OnLocalPlayerRemovedEvent.AddUObject(
|
||||||
|
this, &UOLSGameFeatureAction_AddInputContextMapping::UnregisterInputMappingContextsForLocalPlayer);
|
||||||
|
|
||||||
|
for (TArray<ULocalPlayer*>::TConstIterator localPlayerIterator = gameInstance->GetLocalPlayerIterator();
|
||||||
|
localPlayerIterator; ++localPlayerIterator)
|
||||||
|
{
|
||||||
|
RegisterInputMappingContextsForLocalPlayer(*localPlayerIterator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::RegisterInputMappingContextsForLocalPlayer(ULocalPlayer* localPlayer)
|
||||||
|
{
|
||||||
|
if (ensure(localPlayer))
|
||||||
|
{
|
||||||
|
UOLSAssetManager& assetManager = UOLSAssetManager::Get();
|
||||||
|
|
||||||
|
if (UEnhancedInputLocalPlayerSubsystem* eiSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(localPlayer))
|
||||||
|
{
|
||||||
|
if (UEnhancedInputUserSettings* settings = eiSubsystem->GetUserSettings())
|
||||||
|
{
|
||||||
|
for (const FOLSInputMappingContextAndPriority& entry : InputMappings)
|
||||||
|
{
|
||||||
|
// Skip entries that don't want to be registered
|
||||||
|
if (!entry.bShouldRegisterWithSettings)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this IMC with the settings!
|
||||||
|
if (UInputMappingContext* imc = assetManager.GetAsset(entry.InputMapping))
|
||||||
|
{
|
||||||
|
settings->RegisterInputMappingContext(imc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::UnregisterInputMappingContexts()
|
||||||
|
{
|
||||||
|
FWorldDelegates::OnStartGameInstance.Remove(RegisterInputContextMappingsForGameInstanceHandle);
|
||||||
|
RegisterInputContextMappingsForGameInstanceHandle.Reset();
|
||||||
|
|
||||||
|
const TIndirectArray<FWorldContext>& worldContexts = GEngine->GetWorldContexts();
|
||||||
|
for (TIndirectArray<FWorldContext>::TConstIterator worldContextIterator = worldContexts.CreateConstIterator();
|
||||||
|
worldContextIterator; ++worldContextIterator)
|
||||||
|
{
|
||||||
|
UnregisterInputContextMappingsForGameInstance(worldContextIterator->OwningGameInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::UnregisterInputContextMappingsForGameInstance(
|
||||||
|
UGameInstance* gameInstance)
|
||||||
|
{
|
||||||
|
if (gameInstance)
|
||||||
|
{
|
||||||
|
gameInstance->OnLocalPlayerAddedEvent.RemoveAll(this);
|
||||||
|
gameInstance->OnLocalPlayerRemovedEvent.RemoveAll(this);
|
||||||
|
|
||||||
|
for (TArray<ULocalPlayer*>::TConstIterator localPlayerIterator = gameInstance->GetLocalPlayerIterator();
|
||||||
|
localPlayerIterator; ++localPlayerIterator)
|
||||||
|
{
|
||||||
|
UnregisterInputMappingContextsForLocalPlayer(*localPlayerIterator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::UnregisterInputMappingContextsForLocalPlayer(
|
||||||
|
ULocalPlayer* localPlayer)
|
||||||
|
{
|
||||||
|
if (ensure(localPlayer))
|
||||||
|
{
|
||||||
|
if (UEnhancedInputLocalPlayerSubsystem* eiSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(localPlayer))
|
||||||
|
{
|
||||||
|
if (UEnhancedInputUserSettings* settings = eiSubsystem->GetUserSettings())
|
||||||
|
{
|
||||||
|
for (const FOLSInputMappingContextAndPriority& entry : InputMappings)
|
||||||
|
{
|
||||||
|
// Skip entries that don't want to be registered
|
||||||
|
if (!entry.bShouldRegisterWithSettings)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this IMC with the settings!
|
||||||
|
if (UInputMappingContext* imc = entry.InputMapping.Get())
|
||||||
|
{
|
||||||
|
settings->UnregisterInputMappingContext(imc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::AddToWorld(const FWorldContext& worldContext,
|
||||||
|
const FGameFeatureStateChangeContext& changeContext)
|
||||||
|
{
|
||||||
|
UWorld* world = worldContext.World();
|
||||||
|
UGameInstance* gameInstance = worldContext.OwningGameInstance;
|
||||||
|
FPerContextData& activeData = ContextData.FindOrAdd(changeContext);
|
||||||
|
|
||||||
|
if (gameInstance && world && 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 UOLSGameFeatureAction_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 UOLSGameFeatureAction_AddInputContextMapping::HandleControllerExtension(AActor* actor,
|
||||||
|
FName eventName,
|
||||||
|
FGameFeatureStateChangeContext changeContext)
|
||||||
|
{
|
||||||
|
APlayerController* playerController = 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(playerController, activeData);
|
||||||
|
}
|
||||||
|
else if ((eventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (eventName == UOLSHeroComponent::NAME_BindInputsNow))
|
||||||
|
{
|
||||||
|
AddInputMappingForPlayer(playerController->GetLocalPlayer(), activeData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_AddInputContextMapping::AddInputMappingForPlayer(UPlayer* player,
|
||||||
|
FPerContextData& activeData)
|
||||||
|
{
|
||||||
|
if (ULocalPlayer* localPlayer = Cast<ULocalPlayer>(player))
|
||||||
|
{
|
||||||
|
if (UEnhancedInputLocalPlayerSubsystem* inputSystem = localPlayer->GetSubsystem<
|
||||||
|
UEnhancedInputLocalPlayerSubsystem>())
|
||||||
|
{
|
||||||
|
for (const FOLSInputMappingContextAndPriority& entry : InputMappings)
|
||||||
|
{
|
||||||
|
if (const UInputMappingContext* imc = entry.InputMapping.Get())
|
||||||
|
{
|
||||||
|
inputSystem->AddMappingContext(imc, entry.Priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OLS_LOG(LogOLSGameFA_AddInputContextMapping, 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 UOLSGameFeatureAction_AddInputContextMapping::RemoveInputMapping(APlayerController* playerController,
|
||||||
|
FPerContextData& activeData)
|
||||||
|
{
|
||||||
|
if (ULocalPlayer* localPlayer = playerController->GetLocalPlayer())
|
||||||
|
{
|
||||||
|
if (UEnhancedInputLocalPlayerSubsystem* inputSystem = localPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
|
||||||
|
{
|
||||||
|
for (const FOLSInputMappingContextAndPriority& entry : InputMappings)
|
||||||
|
{
|
||||||
|
if (const UInputMappingContext* imc = entry.InputMapping.Get())
|
||||||
|
{
|
||||||
|
inputSystem->RemoveMappingContext(imc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activeData.ControllersAddedTo.Remove(playerController);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef LOCTEXT_NAMESPACE
|
@ -0,0 +1,46 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
|
||||||
|
#include "GameFeatures/OLSGameFeatureAction_WorldActionBase.h"
|
||||||
|
|
||||||
|
#include "GameFeaturesSubsystem.h"
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_WorldActionBase::OnGameFeatureActivating(FGameFeatureActivatingContext& context)
|
||||||
|
{
|
||||||
|
// Don't call Super since we don't need it.
|
||||||
|
|
||||||
|
GameInstanceStartHandles.FindOrAdd(context) = FWorldDelegates::OnStartGameInstance.AddUObject(this,
|
||||||
|
&UOLSGameFeatureAction_WorldActionBase::HandleGameInstanceStart, FGameFeatureStateChangeContext(context));
|
||||||
|
|
||||||
|
// Add to any worlds with associated game instances that have already been initialized
|
||||||
|
for (const FWorldContext& worldContext : GEngine->GetWorldContexts())
|
||||||
|
{
|
||||||
|
if (context.ShouldApplyToWorldContext(worldContext))
|
||||||
|
{
|
||||||
|
AddToWorld(worldContext, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_WorldActionBase::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& context)
|
||||||
|
{
|
||||||
|
// Don't call Super since we don't need it.
|
||||||
|
|
||||||
|
FDelegateHandle* foundHandle = GameInstanceStartHandles.Find(context);
|
||||||
|
if (ensure(foundHandle))
|
||||||
|
{
|
||||||
|
FWorldDelegates::OnStartGameInstance.Remove(*foundHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UOLSGameFeatureAction_WorldActionBase::HandleGameInstanceStart(UGameInstance* gameInstance,
|
||||||
|
FGameFeatureStateChangeContext changeContext)
|
||||||
|
{
|
||||||
|
if (FWorldContext* worldContext = gameInstance->GetWorldContext())
|
||||||
|
{
|
||||||
|
if (changeContext.ShouldApplyToWorldContext(*worldContext))
|
||||||
|
{
|
||||||
|
AddToWorld(*worldContext, changeContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
Source/ols/Public/AbilitySystem/Abilities/OLSAbilityCost.h
Normal file
61
Source/ols/Public/AbilitySystem/Abilities/OLSAbilityCost.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trad`emark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameplayAbilitySpec.h"
|
||||||
|
#include "GameplayTagContainer.h"
|
||||||
|
#include "Abilities/GameplayAbilityTypes.h"
|
||||||
|
#include "OLSAbilityCost.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UOLSAbilityCost
|
||||||
|
*
|
||||||
|
* Base class for costs that a LyraGameplayAbility has (e.g., ammo or charges)
|
||||||
|
*/
|
||||||
|
UCLASS(DefaultToInstanced, EditInlineNew, Abstract)
|
||||||
|
class OLS_API UOLSAbilityCost : public UObject
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UOLSAbilityCost();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if we can afford this cost.
|
||||||
|
*
|
||||||
|
* A failure reason tag can be added to OptionalRelevantTags (if non-null), which can be queried
|
||||||
|
* elsewhere to determine how to provide user feedback (e.g., a clicking noise if a weapon is out of ammo)
|
||||||
|
*
|
||||||
|
* Ability and ActorInfo are guaranteed to be non-null on entry, but OptionalRelevantTags can be nullptr.
|
||||||
|
*
|
||||||
|
* @return true if we can pay for the ability, false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool CheckCost(const class UOLSGameplayAbility* ability,
|
||||||
|
const FGameplayAbilitySpecHandle handle,
|
||||||
|
const FGameplayAbilityActorInfo* actorInfo,
|
||||||
|
FGameplayTagContainer* optionalRelevantTags) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the ability's cost to the target
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - Your implementation don't need to check ShouldOnlyApplyCostOnHit(), the caller does that for you.
|
||||||
|
* - Ability and ActorInfo are guaranteed to be non-null on entry.
|
||||||
|
*/
|
||||||
|
virtual void ApplyCost(const class UOLSGameplayAbility* ability,
|
||||||
|
const FGameplayAbilitySpecHandle handle,
|
||||||
|
const FGameplayAbilityActorInfo* actorInfo,
|
||||||
|
const FGameplayAbilityActivationInfo activationInfo);
|
||||||
|
|
||||||
|
/** If true, this cost should only be applied if this ability hits successfully */
|
||||||
|
bool ShouldOnlyApplyCostOnHit() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** If true, this cost should only be applied if this ability hits successfully */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OLS|Costs")
|
||||||
|
uint8 bShouldOnlyApplyCostOnHit : 1 = false;
|
||||||
|
};
|
@ -7,10 +7,106 @@
|
|||||||
#include "OLSGameplayAbility.generated.h"
|
#include "OLSGameplayAbility.generated.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* ELyraAbilityActivationPolicy
|
||||||
|
*
|
||||||
|
* Defines how an ability is meant to activate.
|
||||||
*/
|
*/
|
||||||
UCLASS()
|
UENUM(BlueprintType)
|
||||||
|
enum class EOLSAbilityActivationPolicy : uint8
|
||||||
|
{
|
||||||
|
// Try to activate the ability when the input is triggered.
|
||||||
|
OnInputTriggered,
|
||||||
|
|
||||||
|
// Continually try to activate the ability while the input is active.
|
||||||
|
WhileInputActive,
|
||||||
|
|
||||||
|
// Try to activate the ability when an avatar is assigned.
|
||||||
|
OnSpawn
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ELyraAbilityActivationGroup
|
||||||
|
*
|
||||||
|
* Defines how an ability activates in relation to other abilities.
|
||||||
|
*/
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum class EOLSAbilityActivationGroup : uint8
|
||||||
|
{
|
||||||
|
// Ability runs independently of all other abilities.
|
||||||
|
Independent,
|
||||||
|
|
||||||
|
// Ability is canceled and replaced by other exclusive abilities.
|
||||||
|
Exclusive_Replaceable,
|
||||||
|
|
||||||
|
// Ability blocks all other exclusive abilities from activating.
|
||||||
|
Exclusive_Blocking,
|
||||||
|
|
||||||
|
MAX UMETA(Hidden)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Failure reason that can be used to play an animation montage when a failure occurs */
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FOLSAbilityMontageFailureMessage
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Player controller that failed to activate the ability, if the AbilitySystemComponent was player owned
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
TObjectPtr<APlayerController> PlayerController = nullptr;
|
||||||
|
|
||||||
|
// Avatar actor that failed to activate the ability
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
TObjectPtr<AActor> AvatarActor = nullptr;
|
||||||
|
|
||||||
|
// All the reasons why this ability has failed
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
FGameplayTagContainer FailureTags;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
TObjectPtr<UAnimMontage> FailureMontage = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UOLSGameplayAbility
|
||||||
|
*
|
||||||
|
* The base gameplay ability class used by this project.
|
||||||
|
*/
|
||||||
|
UCLASS(Abstract, HideCategories = Input, Meta = (ShortTooltip = "The base gameplay ability class used by this project."))
|
||||||
class OLS_API UOLSGameplayAbility : public UGameplayAbility
|
class OLS_API UOLSGameplayAbility : public UGameplayAbility
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Defines how this ability is meant to activate.
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "OLS|Ability Activation")
|
||||||
|
EOLSAbilityActivationPolicy ActivationPolicy;
|
||||||
|
|
||||||
|
// Defines the relationship between this ability activating and other abilities activating.
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "OLS|Ability Activation")
|
||||||
|
EOLSAbilityActivationGroup ActivationGroup;
|
||||||
|
|
||||||
|
// Additional costs that must be paid to activate this ability
|
||||||
|
UPROPERTY(EditDefaultsOnly, Instanced, Category = Costs)
|
||||||
|
TArray<TObjectPtr<class UOLSAbilityCost>> AdditionalCosts;
|
||||||
|
|
||||||
|
// Map of failure tags to simple error messages
|
||||||
|
UPROPERTY(EditDefaultsOnly, Category = "Advanced")
|
||||||
|
TMap<FGameplayTag, FText> FailureTagToUserFacingMessages;
|
||||||
|
|
||||||
|
// Map of failure tags to anim montages that should be played with them
|
||||||
|
UPROPERTY(EditDefaultsOnly, Category = "Advanced")
|
||||||
|
TMap<FGameplayTag, TObjectPtr<UAnimMontage>> FailureTagToAnimMontage;
|
||||||
|
|
||||||
|
// If true, extra information should be logged when this ability is canceled. This is temporary, used for tracking a bug.
|
||||||
|
UPROPERTY(EditDefaultsOnly, Category = "Advanced")
|
||||||
|
uint8 bShouldLogCancellation : 1 = false;
|
||||||
|
|
||||||
|
// Current camera mode set by the ability.
|
||||||
|
// TSubclassOf<ULyraCameraMode> ActiveCameraMode;
|
||||||
};
|
};
|
||||||
|
94
Source/ols/Public/Components/OLSHeroComponent.h
Normal file
94
Source/ols/Public/Components/OLSHeroComponent.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameplayAbilitySpecHandle.h"
|
||||||
|
#include "Components/GameFrameworkInitStateInterface.h"
|
||||||
|
#include "Components/PawnComponent.h"
|
||||||
|
#include "OLSHeroComponent.generated.h"
|
||||||
|
|
||||||
|
DECLARE_LOG_CATEGORY_EXTERN(LogOLSHeroComponent, Verbose, All);
|
||||||
|
|
||||||
|
namespace EEndPlayReason { enum Type : int; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that sets up input and camera handling for player controlled pawns (or bots that simulate players).
|
||||||
|
* This depends on a PawnExtensionComponent to coordinate initialization.
|
||||||
|
*/
|
||||||
|
UCLASS(Blueprintable, Meta=(BlueprintSpawnableComponent))
|
||||||
|
class OLS_API UOLSHeroComponent : public UPawnComponent, public IGameFrameworkInitStateInterface
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UOLSHeroComponent(const FObjectInitializer& objectInitializer);
|
||||||
|
|
||||||
|
//~ Begin IGameFrameworkInitStateInterface interface
|
||||||
|
virtual FName GetFeatureName() const override;
|
||||||
|
virtual bool CanChangeInitState(UGameFrameworkComponentManager* manager, FGameplayTag currentState, FGameplayTag desiredState) const override;
|
||||||
|
virtual void HandleChangeInitState(UGameFrameworkComponentManager* manager, FGameplayTag currentState, FGameplayTag desiredState) override;
|
||||||
|
virtual void OnActorInitStateChanged(const FActorInitStateChangedParams& params) override;
|
||||||
|
virtual void CheckDefaultInitialization() override;
|
||||||
|
//~ End IGameFrameworkInitStateInterface interface
|
||||||
|
|
||||||
|
/** The name of the extension event sent via UGameFrameworkComponentManager when ability inputs are ready to bind */
|
||||||
|
static const FName NAME_BindInputsNow;
|
||||||
|
|
||||||
|
/** The name of this component-implemented feature */
|
||||||
|
static const FName NAME_ActorFeatureName;
|
||||||
|
|
||||||
|
/** Overrides the camera from an active gameplay ability */
|
||||||
|
//@TODO: implement UOLSCameraMode.
|
||||||
|
// void SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle);
|
||||||
|
|
||||||
|
/** Clears the camera override if it is set */
|
||||||
|
void ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& owningSpecHandle);
|
||||||
|
|
||||||
|
/** Adds mode-specific input config */
|
||||||
|
void AddAdditionalInputConfig(const class UOLSInputConfigDataAsset* inputConfig);
|
||||||
|
|
||||||
|
/** Removes a mode-specific input config if it has been added */
|
||||||
|
void RemoveAdditionalInputConfig(const class UOLSInputConfigDataAsset* inputConfig);
|
||||||
|
|
||||||
|
/** True if this is controlled by a real player and has progressed far enough in initialization where additional input bindings can be added */
|
||||||
|
bool IsReadyToBindInputs() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//~ Begin UActorComponent interface.
|
||||||
|
virtual void OnRegister() override;
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
virtual void EndPlay(const EEndPlayReason::Type endPlayReason) override;
|
||||||
|
//~ End UActorComponent interface.
|
||||||
|
|
||||||
|
virtual void InitializePlayerInput(UInputComponent* playerInputComponent);
|
||||||
|
|
||||||
|
void Input_AbilityInputTagPressed(FGameplayTag inputTag);
|
||||||
|
void Input_AbilityInputTagReleased(FGameplayTag inputTag);
|
||||||
|
|
||||||
|
void Input_Move(const struct FInputActionValue& inputActionValue);
|
||||||
|
void Input_LookMouse(const struct FInputActionValue& inputActionValue);
|
||||||
|
void Input_LookStick(const struct FInputActionValue& inputActionValue);
|
||||||
|
void Input_Crouch(const struct FInputActionValue& InputActionValue);
|
||||||
|
void Input_AutoRun(const struct FInputActionValue& inputActionValue);
|
||||||
|
|
||||||
|
//@TODO: implement UOLSCameraMode.
|
||||||
|
// TSubclassOf<ULyraCameraMode> DetermineCameraMode() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere)
|
||||||
|
TArray<struct FOLSInputMappingContextAndPriority> DefaultInputMappings;
|
||||||
|
|
||||||
|
/** Camera mode set by an ability. */
|
||||||
|
// UPROPERTY()
|
||||||
|
// TSubclassOf<ULyraCameraMode> AbilityCameraMode;
|
||||||
|
|
||||||
|
/** Spec handle for the last ability to set a camera mode. */
|
||||||
|
FGameplayAbilitySpecHandle AbilityCameraModeOwningSpecHandle;
|
||||||
|
|
||||||
|
/** True when player input bindings have been applied, will never be true for non - players */
|
||||||
|
bool bIsReadyToBindInputs;
|
||||||
|
};
|
@ -28,6 +28,10 @@ public:
|
|||||||
/** The name of this overall feature, this one depends on the other named component features */
|
/** The name of this overall feature, this one depends on the other named component features */
|
||||||
static const FName NAME_ActorFeatureName;
|
static const FName NAME_ActorFeatureName;
|
||||||
|
|
||||||
|
//~ Begin UActorComponent interface
|
||||||
|
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||||
|
//~ End UActorComponent interface
|
||||||
|
|
||||||
//~ Begin IGameFrameworkInitStateInterface interface
|
//~ Begin IGameFrameworkInitStateInterface interface
|
||||||
virtual FName GetFeatureName() const override;
|
virtual FName GetFeatureName() const override;
|
||||||
virtual bool CanChangeInitState(UGameFrameworkComponentManager* manager, FGameplayTag currentState, FGameplayTag desiredState) const override;
|
virtual bool CanChangeInitState(UGameFrameworkComponentManager* manager, FGameplayTag currentState, FGameplayTag desiredState) const override;
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "OLSGameFeatureAction_WorldActionBase.h"
|
||||||
|
#include "OLSGameFeatureAction_AddInputContextMapping.generated.h"
|
||||||
|
|
||||||
|
DECLARE_LOG_CATEGORY_EXTERN(LogOLSGameFA_AddInputContextMapping, Verbose, All);
|
||||||
|
|
||||||
|
USTRUCT()
|
||||||
|
struct FOLSInputMappingContextAndPriority
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, Category="Input", meta=(AssetBundles="Client,Server"))
|
||||||
|
TSoftObjectPtr<class UInputMappingContext> InputMapping;
|
||||||
|
|
||||||
|
// Higher priority input mappings will be prioritized over mappings with a lower priority.
|
||||||
|
UPROPERTY(EditAnywhere, Category="Input")
|
||||||
|
int32 Priority = 0;
|
||||||
|
|
||||||
|
/** If true, then this mapping context will be registered with the settings when this game feature action is registered. */
|
||||||
|
UPROPERTY(EditAnywhere, Category="Input")
|
||||||
|
uint8 bShouldRegisterWithSettings : 1 = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds InputMappingContext to local players' EnhancedInput system.
|
||||||
|
* Expects that local players are set up to use the EnhancedInput system.
|
||||||
|
*/
|
||||||
|
UCLASS(MinimalAPI, meta = (DisplayName = "Add Input Mapping"))
|
||||||
|
class UOLSGameFeatureAction_AddInputContextMapping : public UOLSGameFeatureAction_WorldActionBase
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//~ Begin UGameFeatureAction interface
|
||||||
|
virtual void OnGameFeatureRegistering() override;
|
||||||
|
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& context) override;
|
||||||
|
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& context) override;
|
||||||
|
virtual void OnGameFeatureUnregistering() override;
|
||||||
|
//~ End UGameFeatureAction interface
|
||||||
|
|
||||||
|
//~ Begin UObject interface
|
||||||
|
#if WITH_EDITOR
|
||||||
|
virtual EDataValidationResult IsDataValid(class FDataValidationContext& context) const override;
|
||||||
|
#endif
|
||||||
|
//~ End UObject interface
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Registers owned Input Mapping Contexts to the Input Registry Subsystem. Also binds onto the start of GameInstances and the adding/removal of Local Players. */
|
||||||
|
void RegisterInputMappingContexts();
|
||||||
|
|
||||||
|
/** Registers owned Input Mapping Contexts to the Input Registry Subsystem for a specified GameInstance. This also gets called by a GameInstance Start. */
|
||||||
|
void RegisterInputContextMappingsForGameInstance(class UGameInstance* gameInstance);
|
||||||
|
|
||||||
|
/** Registers owned Input Mapping Contexts to the Input Registry Subsystem for a specified Local Player. This also gets called when a Local Player is added. */
|
||||||
|
void RegisterInputMappingContextsForLocalPlayer(class ULocalPlayer* localPlayer);
|
||||||
|
|
||||||
|
/** Unregisters owned Input Mapping Contexts from the Input Registry Subsystem. Also unbinds from the start of GameInstances and the adding/removal of Local Players. */
|
||||||
|
void UnregisterInputMappingContexts();
|
||||||
|
|
||||||
|
/** Unregisters owned Input Mapping Contexts from the Input Registry Subsystem for a specified GameInstance. */
|
||||||
|
void UnregisterInputContextMappingsForGameInstance(class UGameInstance* gameInstance);
|
||||||
|
|
||||||
|
/** Unregisters owned Input Mapping Contexts from the Input Registry Subsystem for a specified Local Player. This also gets called when a Local Player is removed. */
|
||||||
|
void UnregisterInputMappingContextsForLocalPlayer(class ULocalPlayer* localPlayer);
|
||||||
|
|
||||||
|
//~UGameFeatureAction_WorldActionBase interface
|
||||||
|
virtual void AddToWorld(const FWorldContext& worldContext, const struct FGameFeatureStateChangeContext& changeContext) override;
|
||||||
|
//~End of UGameFeatureAction_WorldActionBase interface
|
||||||
|
|
||||||
|
struct FPerContextData
|
||||||
|
{
|
||||||
|
TArray<TSharedPtr<struct FComponentRequestHandle>> ExtensionRequestHandles;
|
||||||
|
TArray<TWeakObjectPtr<class APlayerController>> ControllersAddedTo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Reset(FPerContextData& activeData);
|
||||||
|
void HandleControllerExtension(class AActor* actor, FName eventName, struct FGameFeatureStateChangeContext changeContext);
|
||||||
|
void AddInputMappingForPlayer(class UPlayer* player, struct FPerContextData& activeData);
|
||||||
|
void RemoveInputMapping(class APlayerController* playerController, FPerContextData& activeData);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, Category="Input")
|
||||||
|
TArray<FOLSInputMappingContextAndPriority> InputMappings;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
TMap<struct FGameFeatureStateChangeContext, struct FPerContextData> ContextData;
|
||||||
|
|
||||||
|
/** Delegate for when the game instance is changed to register IMC's */
|
||||||
|
FDelegateHandle RegisterInputContextMappingsForGameInstanceHandle;
|
||||||
|
};
|
@ -0,0 +1,38 @@
|
|||||||
|
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFeatureAction.h"
|
||||||
|
#include "GameFeaturesSubsystem.h"
|
||||||
|
|
||||||
|
#include "OLSGameFeatureAction_WorldActionBase.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for GameFeatureActions that wish to do something world specific.
|
||||||
|
*/
|
||||||
|
UCLASS(Abstract)
|
||||||
|
class OLS_API UOLSGameFeatureAction_WorldActionBase : public UGameFeatureAction
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//~ Begin UGameFeatureAction interface
|
||||||
|
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& context) override;
|
||||||
|
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& context) override;
|
||||||
|
//~ End UGameFeatureAction interface
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void HandleGameInstanceStart(UGameInstance* gameInstance, FGameFeatureStateChangeContext changeContext);
|
||||||
|
|
||||||
|
/** Override with the action-specific logic */
|
||||||
|
virtual void AddToWorld(const FWorldContext& worldContext,
|
||||||
|
const FGameFeatureStateChangeContext& changeContext) PURE_VIRTUAL(
|
||||||
|
UOLSGameFeatureAction_WorldActionBase::AddToWorld);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
TMap<FGameFeatureStateChangeContext, FDelegateHandle> GameInstanceStartHandles;
|
||||||
|
};
|
@ -27,7 +27,8 @@ public class ols : ModuleRules
|
|||||||
"InputCore",
|
"InputCore",
|
||||||
"AnimGraphRuntime",
|
"AnimGraphRuntime",
|
||||||
"GameplayMessageRuntime",
|
"GameplayMessageRuntime",
|
||||||
"NetCore"
|
"NetCore",
|
||||||
|
"EnhancedInput",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Header files path
|
// Header files path
|
||||||
@ -43,5 +44,8 @@ public class ols : ModuleRules
|
|||||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||||
|
|
||||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||||
|
|
||||||
|
|
||||||
|
SetupGameplayDebuggerSupport(Target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user