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,
|
||||
TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."),
|
||||
UOLSGameDataAsset::Get().DynamicTagGameplayEffect.GetAssetName());
|
||||
*UOLSGameDataAsset::Get().DynamicTagGameplayEffect.GetAssetName());
|
||||
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 "Components/GameFrameworkComponentManager.h"
|
||||
#include "DataAssets/OLSPawnDataAsset.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOLSPawnExtensionComponent);
|
||||
|
||||
const FName UOLSPawnExtensionComponent::NAME_ActorFeatureName("PawnExtension");
|
||||
|
||||
UOLSPawnExtensionComponent::UOLSPawnExtensionComponent(const FObjectInitializer& objectInitializer)
|
||||
: Super(objectInitializer)
|
||||
{
|
||||
@ -22,6 +25,13 @@ UOLSPawnExtensionComponent::UOLSPawnExtensionComponent(const FObjectInitializer&
|
||||
AbilitySystemComponent = nullptr;
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(UOLSPawnExtensionComponent, PawnData);
|
||||
}
|
||||
|
||||
FName UOLSPawnExtensionComponent::GetFeatureName() const
|
||||
{
|
||||
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"
|
||||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
{
|
||||
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 */
|
||||
static const FName NAME_ActorFeatureName;
|
||||
|
||||
//~ Begin UActorComponent interface
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
//~ End UActorComponent interface
|
||||
|
||||
//~ Begin IGameFrameworkInitStateInterface interface
|
||||
virtual FName GetFeatureName() 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",
|
||||
"AnimGraphRuntime",
|
||||
"GameplayMessageRuntime",
|
||||
"NetCore"
|
||||
"NetCore",
|
||||
"EnhancedInput",
|
||||
});
|
||||
|
||||
// Header files path
|
||||
@ -43,5 +44,8 @@ public class ols : ModuleRules
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// 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