Implemented OLSPawnExtensionComponent.
Added some functionalities for OLSAbilitySystemComponent
This commit is contained in:
parent
e0545d6323
commit
51306c57a9
@ -8,10 +8,16 @@
|
||||
#include "OLSLog.h"
|
||||
#include "AbilitySystem/OLSBatchGameplayAbilityInterface.h"
|
||||
#include "AbilitySystem/OLSGlobaAbilitySubsystem.h"
|
||||
#include "AbilitySystem/Abilities/OLSGameplayAbility.h"
|
||||
#include "AnimInstances/OLSBaseLayerAnimInstance.h"
|
||||
#include "DataAssets/OLSAbilityTagRelationshipMappingDataAsset.h"
|
||||
#include "DataAssets/OLSGameDataAsset.h"
|
||||
#include "Systems/OLSAssetManager.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOLSAbilitySystemComponent);
|
||||
|
||||
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked");
|
||||
|
||||
// Sets default values for this component's properties
|
||||
UOLSAbilitySystemComponent::UOLSAbilitySystemComponent()
|
||||
{
|
||||
@ -292,10 +298,142 @@ void UOLSAbilitySystemComponent::RemoveGameplayCueLocally(
|
||||
void UOLSAbilitySystemComponent::TryActivateAbilitiesOnSpawn()
|
||||
{
|
||||
ABILITYLIST_SCOPE_LOCK();
|
||||
|
||||
for (const FGameplayAbilitySpec& abilitySpec : GetActivatableAbilities())
|
||||
for (const FGameplayAbilitySpec& abilitySpec : ActivatableAbilities.Items)
|
||||
{
|
||||
// if (const UOLS)
|
||||
if (const UOLSGameplayAbility* abilityCDO = Cast<UOLSGameplayAbility>(abilitySpec.Ability))
|
||||
{
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// abilityCDO->TryActivateAbilityOnSpawn(AbilityActorInfo.Get(), abilitySpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::AbilitySpecInputPressed(FGameplayAbilitySpec& spec)
|
||||
{
|
||||
Super::AbilitySpecInputPressed(spec);
|
||||
|
||||
// We don't support UGameplayAbility::bReplicateInputDirectly.
|
||||
// Use replicated events instead so that the WaitInputPress ability task works.
|
||||
if (spec.IsActive())
|
||||
{
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
const UGameplayAbility* instance = spec.GetPrimaryInstance();
|
||||
FPredictionKey originalPredictionKey = instance
|
||||
? instance->GetCurrentActivationInfo().GetActivationPredictionKey()
|
||||
: spec.ActivationInfo.GetActivationPredictionKey();
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.
|
||||
InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, spec.Handle, originalPredictionKey);
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::AbilitySpecInputReleased(FGameplayAbilitySpec& spec)
|
||||
{
|
||||
Super::AbilitySpecInputReleased(spec);
|
||||
|
||||
// We don't support UGameplayAbility::bReplicateInputDirectly.
|
||||
// Use replicated events instead so that the WaitInputRelease ability task works.
|
||||
if (spec.IsActive())
|
||||
{
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
const UGameplayAbility* instance = spec.GetPrimaryInstance();
|
||||
FPredictionKey originalPredictionKey = instance
|
||||
? instance->GetCurrentActivationInfo().GetActivationPredictionKey()
|
||||
: spec.ActivationInfo.GetActivationPredictionKey();
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// Invoke the InputReleased event. This is not replicated here. If someone is listening, they may replicate the InputReleased event to the server.
|
||||
InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, spec.Handle, originalPredictionKey);
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::NotifyAbilityActivated(const FGameplayAbilitySpecHandle handle,
|
||||
UGameplayAbility* ability)
|
||||
{
|
||||
Super::NotifyAbilityActivated(handle, ability);
|
||||
|
||||
if (UOLSGameplayAbility* olsAbility = Cast<UOLSGameplayAbility>(ability))
|
||||
{
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// AddAbilityToActivationGroup(olsAbility->GetActivationGroup(), ability);
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::NotifyAbilityFailed(const FGameplayAbilitySpecHandle handle,
|
||||
UGameplayAbility* ability,
|
||||
const FGameplayTagContainer& failureReason)
|
||||
{
|
||||
Super::NotifyAbilityFailed(handle, ability, failureReason);
|
||||
|
||||
if (APawn* avatar = Cast<APawn>(GetAvatarActor()))
|
||||
{
|
||||
if (!avatar->IsLocallyControlled() && ability->IsSupportedForNetworking())
|
||||
{
|
||||
ClientNotifyAbilityFailed(ability, failureReason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HandleAbilityFailed(ability, failureReason);
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::NotifyAbilityEnded(FGameplayAbilitySpecHandle handle, UGameplayAbility* Ability,
|
||||
bool wasCancelled)
|
||||
{
|
||||
Super::NotifyAbilityEnded(handle, Ability, wasCancelled);
|
||||
|
||||
if (UOLSGameplayAbility* olsAbility = Cast<UOLSGameplayAbility>(Ability))
|
||||
{
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// RemoveAbilityFromActivationGroup(olsAbility->GetActivationGroup(), olsAbility);
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& abilityTags,
|
||||
UGameplayAbility* requestingAbility,
|
||||
bool shouldEnableBlockTags,
|
||||
const FGameplayTagContainer& blockTags,
|
||||
bool shouldExecuteCancelTags,
|
||||
const FGameplayTagContainer& cancelTags)
|
||||
{
|
||||
FGameplayTagContainer modifiedBlockTags = blockTags;
|
||||
FGameplayTagContainer modifiedCancelTags = cancelTags;
|
||||
|
||||
if (TagRelationshipMapping)
|
||||
{
|
||||
// Use the mapping to expand the ability tags into block and cancel tag
|
||||
TagRelationshipMapping->GetAbilityTagsToBlockAndCancel(abilityTags, &modifiedBlockTags, &modifiedCancelTags);
|
||||
}
|
||||
|
||||
Super::ApplyAbilityBlockAndCancelTags(abilityTags, requestingAbility, shouldEnableBlockTags, modifiedBlockTags,
|
||||
shouldExecuteCancelTags, modifiedCancelTags);
|
||||
|
||||
//@TODO: Apply any special logic like blocking input or movement
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& abilityTags,
|
||||
UGameplayAbility* requestingAbility,
|
||||
bool canBeCanceled)
|
||||
{
|
||||
Super::HandleChangeAbilityCanBeCanceled(abilityTags, requestingAbility, canBeCanceled);
|
||||
|
||||
//@TODO: Apply any special logic like blocking input or movement
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::ClientNotifyAbilityFailed_Implementation(const UGameplayAbility* ability,
|
||||
const FGameplayTagContainer& failureReason)
|
||||
{
|
||||
HandleAbilityFailed(ability, failureReason);
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::HandleAbilityFailed(const UGameplayAbility* ability,
|
||||
const FGameplayTagContainer& failureReason)
|
||||
{
|
||||
if (const UOLSGameplayAbility* olsAbility = Cast<const UOLSGameplayAbility>(ability))
|
||||
{
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// olsAbility->OnAbilityFailedToActivate(failureReason);
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,4 +465,271 @@ void UOLSAbilitySystemComponent::SetReplicatedMontageInfo(
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::CancelAbilitiesByFunc(TShouldCancelAbilityFunc shouldCancelFunc,
|
||||
bool shouldReplicateCancelAbility)
|
||||
{
|
||||
ABILITYLIST_SCOPE_LOCK();
|
||||
for (const FGameplayAbilitySpec& abilitySpec : ActivatableAbilities.Items)
|
||||
{
|
||||
if (!abilitySpec.IsActive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UOLSGameplayAbility* abilityCDO = Cast<UOLSGameplayAbility>(abilitySpec.Ability);
|
||||
if (!abilityCDO)
|
||||
{
|
||||
OLS_LOG(LogOLSAbilitySystemComponent, Error,
|
||||
TEXT("CancelAbilitiesByFunc: Non-LyraGameplayAbility %s was Granted to ASC. Skipping."),
|
||||
GET_UOBJECT_NAME(abilitySpec.Ability));
|
||||
continue;
|
||||
}
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
ensureMsgf(abilitySpec.Ability->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced, TEXT("CancelAbilitiesByFunc: All Abilities should be Instanced (NonInstanced is being deprecated due to usability issues)."));
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// Cancel all the spawned instances.
|
||||
TArray<UGameplayAbility*> Instances = abilitySpec.GetAbilityInstances();
|
||||
for (UGameplayAbility* AbilityInstance : Instances)
|
||||
{
|
||||
UOLSGameplayAbility* abilityInstance = CastChecked<UOLSGameplayAbility>(AbilityInstance);
|
||||
|
||||
if (shouldCancelFunc(abilityInstance, abilitySpec.Handle))
|
||||
{
|
||||
if (abilityInstance->CanBeCanceled())
|
||||
{
|
||||
abilityInstance->CancelAbility(abilitySpec.Handle, AbilityActorInfo.Get(), abilityInstance->GetCurrentActivationInfo(), shouldReplicateCancelAbility);
|
||||
}
|
||||
else
|
||||
{
|
||||
OLS_LOG(LogOLSAbilitySystemComponent, Error,
|
||||
TEXT("CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false."),
|
||||
GET_UOBJECT_NAME(abilityInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::CancelInputActivatedAbilities(bool shouldReplicateCancelAbility)
|
||||
{
|
||||
// @TODO: Implement UOLSGameplayAbility
|
||||
// auto shouldCancelFunc = [this](const UOLSGameplayAbility* ability, FGameplayAbilitySpecHandle handle)
|
||||
// {
|
||||
// const ELyraAbilityActivationPolicy ActivationPolicy = ability->GetActivationPolicy();
|
||||
// return ((ActivationPolicy == ELyraAbilityActivationPolicy::OnInputTriggered) || (ActivationPolicy == ELyraAbilityActivationPolicy::WhileInputActive));
|
||||
// };
|
||||
//
|
||||
// CancelAbilitiesByFunc(shouldCancelFunc, shouldReplicateCancelAbility);
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::AbilityInputTagPressed(const FGameplayTag& inputTag)
|
||||
{
|
||||
if (inputTag.IsValid())
|
||||
{
|
||||
for (const FGameplayAbilitySpec& abilitySpec : ActivatableAbilities.Items)
|
||||
{
|
||||
if (abilitySpec.Ability && (abilitySpec.GetDynamicSpecSourceTags().HasTagExact(inputTag)))
|
||||
{
|
||||
InputPressedSpecHandles.AddUnique(abilitySpec.Handle);
|
||||
InputHeldSpecHandles.AddUnique(abilitySpec.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::AbilityInputTagReleased(const FGameplayTag& inputTag)
|
||||
{
|
||||
if (inputTag.IsValid())
|
||||
{
|
||||
for (const FGameplayAbilitySpec& abilitySpec : ActivatableAbilities.Items)
|
||||
{
|
||||
if (abilitySpec.Ability && (abilitySpec.GetDynamicSpecSourceTags().HasTagExact(inputTag)))
|
||||
{
|
||||
InputReleasedSpecHandles.AddUnique(abilitySpec.Handle);
|
||||
InputHeldSpecHandles.Remove(abilitySpec.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::ProcessAbilityInput(float deltaTime, bool shouldGamePaused)
|
||||
{
|
||||
if (HasMatchingGameplayTag(TAG_Gameplay_AbilityInputBlocked))
|
||||
{
|
||||
ClearAbilityInput();
|
||||
return;
|
||||
}
|
||||
|
||||
static TArray<FGameplayAbilitySpecHandle> abilitiesToActivate;
|
||||
abilitiesToActivate.Reset();
|
||||
|
||||
//@TODO: See if we can use FScopedServerAbilityRPCBatcher ScopedRPCBatcher in some of these loops
|
||||
|
||||
//
|
||||
// Process all abilities that activate when the input is held.
|
||||
//
|
||||
for (const FGameplayAbilitySpecHandle& specHandle : InputHeldSpecHandles)
|
||||
{
|
||||
if (const FGameplayAbilitySpec* abilitySpec = FindAbilitySpecFromHandle(specHandle))
|
||||
{
|
||||
if (abilitySpec->Ability && !abilitySpec->IsActive())
|
||||
{
|
||||
const UOLSGameplayAbility* abilityCDO = Cast<UOLSGameplayAbility>(abilitySpec->Ability);
|
||||
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// if (abilityCDO && abilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::WhileInputActive)
|
||||
// {
|
||||
// AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Process all abilities that had their input pressed this frame.
|
||||
//
|
||||
for (const FGameplayAbilitySpecHandle& specHandle : InputPressedSpecHandles)
|
||||
{
|
||||
if (FGameplayAbilitySpec* abilitySpec = FindAbilitySpecFromHandle(specHandle))
|
||||
{
|
||||
if (abilitySpec->Ability)
|
||||
{
|
||||
abilitySpec->InputPressed = true;
|
||||
|
||||
if (abilitySpec->IsActive())
|
||||
{
|
||||
// Ability is active so pass along the input event.
|
||||
AbilitySpecInputPressed(*abilitySpec);
|
||||
}
|
||||
else
|
||||
{
|
||||
const UOLSGameplayAbility* abilityCDO = Cast<UOLSGameplayAbility>(abilitySpec->Ability);
|
||||
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// if (abilityCDO && abilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::OnInputTriggered)
|
||||
// {
|
||||
// abilitiesToActivate.AddUnique(abilitySpec->Handle);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Try to activate all the abilities that are from presses and holds.
|
||||
// We do it all at once so that held inputs don't activate the ability
|
||||
// and then also send a input event to the ability because of the press.
|
||||
//
|
||||
for (const FGameplayAbilitySpecHandle& abilitySpecHandle : abilitiesToActivate)
|
||||
{
|
||||
TryActivateAbility(abilitySpecHandle);
|
||||
}
|
||||
|
||||
//
|
||||
// Process all abilities that had their input released this frame.
|
||||
//
|
||||
for (const FGameplayAbilitySpecHandle& specHandle : InputReleasedSpecHandles)
|
||||
{
|
||||
if (FGameplayAbilitySpec* abilitySpec = FindAbilitySpecFromHandle(specHandle))
|
||||
{
|
||||
if (abilitySpec->Ability)
|
||||
{
|
||||
abilitySpec->InputPressed = false;
|
||||
|
||||
if (abilitySpec->IsActive())
|
||||
{
|
||||
// Ability is active so pass along the input event.
|
||||
AbilitySpecInputReleased(*abilitySpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Clear the cached ability handles.
|
||||
//
|
||||
InputPressedSpecHandles.Reset();
|
||||
InputReleasedSpecHandles.Reset();
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::ClearAbilityInput()
|
||||
{
|
||||
InputPressedSpecHandles.Reset();
|
||||
InputReleasedSpecHandles.Reset();
|
||||
InputHeldSpecHandles.Reset();
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& tag)
|
||||
{
|
||||
const TSubclassOf<UGameplayEffect> dynamicTagGE = UOLSAssetManager::GetSubclass(UOLSGameDataAsset::Get().DynamicTagGameplayEffect);
|
||||
if (!dynamicTagGE)
|
||||
{
|
||||
OLS_LOG(LogOLSAbilitySystemComponent, Warning,
|
||||
TEXT("AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]."),
|
||||
*UOLSGameDataAsset::Get().DynamicTagGameplayEffect.GetAssetName());
|
||||
return;
|
||||
}
|
||||
|
||||
const FGameplayEffectSpecHandle specHandle = MakeOutgoingSpec(dynamicTagGE, 1.0f, MakeEffectContext());
|
||||
FGameplayEffectSpec* spec = specHandle.Data.Get();
|
||||
|
||||
if (!spec)
|
||||
{
|
||||
OLS_LOG(LogOLSAbilitySystemComponent, Warning,
|
||||
TEXT("AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]."),
|
||||
GET_UOBJECT_NAME(dynamicTagGE));
|
||||
return;
|
||||
}
|
||||
|
||||
spec->DynamicGrantedTags.AddTag(tag);
|
||||
|
||||
ApplyGameplayEffectSpecToSelf(*spec);
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag)
|
||||
{
|
||||
const TSubclassOf<UGameplayEffect> dynamicTagGE = UOLSAssetManager::GetSubclass(UOLSGameDataAsset::Get().DynamicTagGameplayEffect);
|
||||
if (!dynamicTagGE)
|
||||
{
|
||||
OLS_LOG(LogOLSAbilitySystemComponent, Warning,
|
||||
TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."),
|
||||
UOLSGameDataAsset::Get().DynamicTagGameplayEffect.GetAssetName());
|
||||
return;
|
||||
}
|
||||
|
||||
FGameplayEffectQuery query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(FGameplayTagContainer(Tag));
|
||||
query.EffectDefinition = dynamicTagGE;
|
||||
|
||||
RemoveActiveEffects(query);
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::GetAbilityTargetData(const FGameplayAbilitySpecHandle abilityHandle,
|
||||
FGameplayAbilityActivationInfo activationInfo,
|
||||
FGameplayAbilityTargetDataHandle& outTargetDataHandle)
|
||||
{
|
||||
TSharedPtr<FAbilityReplicatedDataCache> replicatedData = AbilityTargetDataMap.Find(
|
||||
FGameplayAbilitySpecHandleAndPredictionKey(abilityHandle, activationInfo.GetActivationPredictionKey()));
|
||||
if (replicatedData.IsValid())
|
||||
{
|
||||
outTargetDataHandle = replicatedData->TargetData;
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::SetTagRelationshipMapping(UOLSAbilityTagRelationshipMappingDataAsset* newMapping)
|
||||
{
|
||||
TagRelationshipMapping = newMapping;
|
||||
}
|
||||
|
||||
void UOLSAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags,
|
||||
FGameplayTagContainer& outActivationRequired,
|
||||
FGameplayTagContainer& outActivationBlocked) const
|
||||
{
|
||||
if (TagRelationshipMapping)
|
||||
{
|
||||
TagRelationshipMapping->GetRequiredAndBlockedActivationTags(abilityTags, &outActivationRequired, &outActivationBlocked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
304
Source/ols/Private/Components/OLSPawnExtensionComponent.cpp
Normal file
304
Source/ols/Private/Components/OLSPawnExtensionComponent.cpp
Normal file
@ -0,0 +1,304 @@
|
||||
// © 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/OLSPawnExtensionComponent.h"
|
||||
|
||||
#include "OLSLog.h"
|
||||
#include "AbilitySystem/OLSAbilitySystemComponent.h"
|
||||
#include "Components/GameFrameworkComponentManager.h"
|
||||
#include "DataAssets/OLSPawnDataAsset.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogOLSPawnExtensionComponent);
|
||||
|
||||
UOLSPawnExtensionComponent::UOLSPawnExtensionComponent(const FObjectInitializer& objectInitializer)
|
||||
: Super(objectInitializer)
|
||||
{
|
||||
PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
|
||||
SetIsReplicatedByDefault(true);
|
||||
|
||||
PawnData = nullptr;
|
||||
AbilitySystemComponent = nullptr;
|
||||
}
|
||||
|
||||
FName UOLSPawnExtensionComponent::GetFeatureName() const
|
||||
{
|
||||
return NAME_ActorFeatureName;
|
||||
}
|
||||
|
||||
bool UOLSPawnExtensionComponent::CanChangeInitState(
|
||||
UGameFrameworkComponentManager* manager,
|
||||
FGameplayTag currentState,
|
||||
FGameplayTag desiredState) const
|
||||
{
|
||||
check(manager);
|
||||
|
||||
APawn* pawn = GetPawn<APawn>();
|
||||
|
||||
// @TODO: Implement LyraGameplayTags::InitState_Spawned.
|
||||
if (!currentState.IsValid() /* && desiredState == LyraGameplayTags::InitState_Spawned */)
|
||||
{
|
||||
// As long as we are on a valid pawn, we count as spawned
|
||||
if (pawn)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: Implement LyraGameplayTags::InitState_Spawned,
|
||||
// @TODO: Implement LyraGameplayTags::InitState_DataAvailable,
|
||||
// @TODO: Implement LyraGameplayTags::InitState_DataInitialized,
|
||||
// @TODO: Implement LyraGameplayTags::InitState_GameplayReady
|
||||
// if (currentState == LyraGameplayTags::InitState_Spawned && desiredState == LyraGameplayTags::InitState_DataAvailable)
|
||||
// {
|
||||
// // Pawn data is required.
|
||||
// if (!PawnData)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// const bool bHasAuthority = pawn->HasAuthority();
|
||||
// const bool bIsLocallyControlled = pawn->IsLocallyControlled();
|
||||
//
|
||||
// if (bHasAuthority || bIsLocallyControlled)
|
||||
// {
|
||||
// // Check for being possessed by a controller.
|
||||
// if (!GetController<AController>())
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
// else if (currentState == LyraGameplayTags::InitState_DataAvailable && desiredState == LyraGameplayTags::InitState_DataInitialized)
|
||||
// {
|
||||
// // Transition to initialize if all features have their data available
|
||||
// return manager->HaveAllFeaturesReachedInitState(pawn, LyraGameplayTags::InitState_DataAvailable);
|
||||
// }
|
||||
// else if (currentState == LyraGameplayTags::InitState_DataInitialized && desiredState == LyraGameplayTags::InitState_GameplayReady)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::HandleChangeInitState(
|
||||
UGameFrameworkComponentManager* manager,
|
||||
FGameplayTag currentState,
|
||||
FGameplayTag desiredState)
|
||||
{
|
||||
// @TODO: Implement LyraGameplayTags::InitState_Spawned.
|
||||
// if (desiredState == LyraGameplayTags::InitState_DataInitialized)
|
||||
// {
|
||||
// // This is currently all handled by other components listening to this state change
|
||||
// }
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::OnActorInitStateChanged(const FActorInitStateChangedParams& Params)
|
||||
{
|
||||
// If another feature is now in DataAvailable, see if we should transition to DataInitialized
|
||||
if (Params.FeatureName != NAME_ActorFeatureName)
|
||||
{
|
||||
// @TODO: Implement LyraGameplayTags::InitState_DataAvailable.
|
||||
// if (Params.FeatureState == LyraGameplayTags::InitState_DataAvailable)
|
||||
// {
|
||||
// CheckDefaultInitialization();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::CheckDefaultInitialization()
|
||||
{
|
||||
// Before checking our progress, try progressing any other features we might depend on
|
||||
CheckDefaultInitializationForImplementers();
|
||||
|
||||
// @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);
|
||||
}
|
||||
|
||||
UOLSPawnExtensionComponent* UOLSPawnExtensionComponent::FindPawnExtensionComponent(const AActor* actor)
|
||||
{
|
||||
return (actor ? actor->FindComponentByClass<UOLSPawnExtensionComponent>() : nullptr);
|
||||
}
|
||||
|
||||
UOLSAbilitySystemComponent* UOLSPawnExtensionComponent::GetOLSAbilitySystemComponent() const
|
||||
{
|
||||
return AbilitySystemComponent;
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::SetPawnData(const UOLSPawnDataAsset* pawnData)
|
||||
{
|
||||
check(pawnData);
|
||||
|
||||
APawn* pawn = GetPawnChecked<APawn>();
|
||||
|
||||
if (pawn->GetLocalRole() != ROLE_Authority)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (PawnData)
|
||||
{
|
||||
OLS_LOG(LogOLSPawnExtensionComponent, Error,
|
||||
TEXT("Trying to set PawnData [%s] on pawn [%s] that already has valid PawnData [%s]."),
|
||||
GET_UOBJECT_NAME(pawnData), GET_UOBJECT_NAME(pawn), GET_UOBJECT_NAME(PawnData));
|
||||
return;
|
||||
}
|
||||
|
||||
PawnData = pawnData;
|
||||
|
||||
pawn->ForceNetUpdate();
|
||||
|
||||
CheckDefaultInitialization();
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::InitializeAbilitySystem(UOLSAbilitySystemComponent* asc, AActor* ownerActor)
|
||||
{
|
||||
check(asc);
|
||||
check(ownerActor);
|
||||
|
||||
if (AbilitySystemComponent == asc)
|
||||
{
|
||||
// The ability system component hasn't changed.
|
||||
return;
|
||||
}
|
||||
|
||||
if (AbilitySystemComponent)
|
||||
{
|
||||
// Clean up the old ability system component.
|
||||
UninitializeAbilitySystem();
|
||||
}
|
||||
|
||||
APawn* pawn = GetPawnChecked<APawn>();
|
||||
AActor* existingAvatar = asc->GetAvatarActor();
|
||||
|
||||
OLS_LOG(LogOLSPawnExtensionComponent, Verbose, TEXT("Setting up ASC [%s] on pawn [%s] owner [%s], existing [%s] "),
|
||||
GET_UOBJECT_NAME(asc), GET_UOBJECT_NAME(pawn), GET_UOBJECT_NAME(ownerActor),
|
||||
GET_UOBJECT_NAME(existingAvatar));
|
||||
|
||||
if ((existingAvatar != nullptr) && (existingAvatar != pawn))
|
||||
{
|
||||
OLS_LOG(LogOLSPawnExtensionComponent, Log, TEXT("Existing avatar (authority=%d)"), existingAvatar->HasAuthority() ? 1 : 0);
|
||||
|
||||
// There is already a pawn acting as the ASC's avatar, so we need to kick it out
|
||||
// This can happen on clients if they're lagged: their new pawn is spawned + possessed before the dead one is removed
|
||||
ensure(!existingAvatar->HasAuthority());
|
||||
|
||||
if (UOLSPawnExtensionComponent* OtherExtensionComponent = FindPawnExtensionComponent(existingAvatar))
|
||||
{
|
||||
OtherExtensionComponent->UninitializeAbilitySystem();
|
||||
}
|
||||
}
|
||||
|
||||
AbilitySystemComponent = asc;
|
||||
AbilitySystemComponent->InitAbilityActorInfo(ownerActor, pawn);
|
||||
|
||||
if (ensure(PawnData))
|
||||
{
|
||||
asc->SetTagRelationshipMapping(PawnData->TagRelationshipMapping);
|
||||
}
|
||||
|
||||
OnAbilitySystemInitialized.Broadcast();
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::UninitializeAbilitySystem()
|
||||
{
|
||||
if (!AbilitySystemComponent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Uninitialize the ASC if we're still the avatar actor (otherwise another pawn already did it when they became the avatar actor)
|
||||
if (AbilitySystemComponent->GetAvatarActor() == GetOwner())
|
||||
{
|
||||
FGameplayTagContainer abilityTypesToIgnore;
|
||||
|
||||
// @TOD:; Implement LyraGameplayTags::Ability_Behavior_SurvivesDeath;
|
||||
// abilityTypesToIgnore.AddTag(LyraGameplayTags::Ability_Behavior_SurvivesDeath);
|
||||
|
||||
AbilitySystemComponent->CancelAbilities(nullptr, &abilityTypesToIgnore);
|
||||
AbilitySystemComponent->ClearAbilityInput();
|
||||
AbilitySystemComponent->RemoveAllGameplayCues();
|
||||
|
||||
if (AbilitySystemComponent->GetOwnerActor() != nullptr)
|
||||
{
|
||||
AbilitySystemComponent->SetAvatarActor(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the ASC doesn't have a valid owner, we need to clear *all* actor info, not just the avatar pairing
|
||||
AbilitySystemComponent->ClearActorInfo();
|
||||
}
|
||||
|
||||
OnAbilitySystemUninitialized.Broadcast();
|
||||
}
|
||||
|
||||
AbilitySystemComponent = nullptr;
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::HandleControllerChanged()
|
||||
{
|
||||
if (AbilitySystemComponent && (AbilitySystemComponent->GetAvatarActor() == GetPawnChecked<APawn>()))
|
||||
{
|
||||
ensure(AbilitySystemComponent->AbilityActorInfo->OwnerActor == AbilitySystemComponent->GetOwnerActor());
|
||||
if (AbilitySystemComponent->GetOwnerActor() == nullptr)
|
||||
{
|
||||
UninitializeAbilitySystem();
|
||||
}
|
||||
else
|
||||
{
|
||||
AbilitySystemComponent->RefreshAbilityActorInfo();
|
||||
}
|
||||
}
|
||||
|
||||
CheckDefaultInitialization();
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::HandlePlayerStateReplicated()
|
||||
{
|
||||
CheckDefaultInitialization();
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::SetupPlayerInputComponent()
|
||||
{
|
||||
CheckDefaultInitialization();
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::OnAbilitySystemInitialized_RegisterAndCall(
|
||||
FSimpleMulticastDelegate::FDelegate delegate)
|
||||
{
|
||||
if (!OnAbilitySystemInitialized.IsBoundToObject(delegate.GetUObject()))
|
||||
{
|
||||
OnAbilitySystemInitialized.Add(delegate);
|
||||
}
|
||||
|
||||
if (AbilitySystemComponent)
|
||||
{
|
||||
delegate.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate delegate)
|
||||
{
|
||||
if (!OnAbilitySystemUninitialized.IsBoundToObject(delegate.GetUObject()))
|
||||
{
|
||||
OnAbilitySystemUninitialized.Add(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
void UOLSPawnExtensionComponent::OnRep_PawnData()
|
||||
{
|
||||
CheckDefaultInitialization();
|
||||
}
|
@ -4,10 +4,13 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "NativeGameplayTags.h"
|
||||
#include "OLSAbilitySystemComponent.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOLSAbilitySystemComponent, Verbose, All);
|
||||
|
||||
OLS_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_AbilityInputBlocked);
|
||||
|
||||
/**
|
||||
* CVAR to control the "Play Montage" flow.
|
||||
* Example: OLS.EnableDefaultPlayMontage true
|
||||
@ -44,7 +47,6 @@ public:
|
||||
float startTimeSeconds) override;
|
||||
// -- End Ability System Component implementation
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -152,13 +154,79 @@ protected:
|
||||
*/
|
||||
void TryActivateAbilitiesOnSpawn();
|
||||
|
||||
virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& spec) override;
|
||||
virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& spec) override;
|
||||
|
||||
virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle handle, UGameplayAbility* ability) override;
|
||||
virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle handle, UGameplayAbility* ability, const FGameplayTagContainer& failureReason) override;
|
||||
virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle handle, UGameplayAbility* Ability, bool bWasCancelled) override;
|
||||
virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& abilityTags, UGameplayAbility* requestingAbility, bool shouldEnableBlockTags, const FGameplayTagContainer& blockTags, bool shouldExecuteCancelTags, const FGameplayTagContainer& cancelTags) override;
|
||||
virtual void HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& abilityTags, UGameplayAbility* requestingAbility, bool canBeCanceled) override;
|
||||
|
||||
/** Notify client that an ability failed to activate */
|
||||
UFUNCTION(Client, Unreliable)
|
||||
void ClientNotifyAbilityFailed(const UGameplayAbility* ability, const FGameplayTagContainer& failureReason);
|
||||
|
||||
void HandleAbilityFailed(const UGameplayAbility* ability, const FGameplayTagContainer& failureReason);
|
||||
|
||||
/**
|
||||
* Conveniently separates the code that sets the animation to replicate, so it can be further modified.
|
||||
*/
|
||||
virtual void SetReplicatedMontageInfo(FGameplayAbilityRepAnimMontage& mutableRepAnimMontageInfo, UAnimMontage* newMontageToPlay, const FName& startSectionName);
|
||||
|
||||
public:
|
||||
|
||||
typedef TFunctionRef<bool(const class UOLSGameplayAbility* ability, FGameplayAbilitySpecHandle handle)> TShouldCancelAbilityFunc;
|
||||
void CancelAbilitiesByFunc(TShouldCancelAbilityFunc shouldCancelFunc, bool shouldReplicateCancelAbility);
|
||||
|
||||
void CancelInputActivatedAbilities(bool shouldReplicateCancelAbility);
|
||||
|
||||
void AbilityInputTagPressed(const FGameplayTag& inputTag);
|
||||
void AbilityInputTagReleased(const FGameplayTag& inputTag);
|
||||
|
||||
void ProcessAbilityInput(float deltaTime, bool shouldGamePaused);
|
||||
void ClearAbilityInput();
|
||||
|
||||
// @TODO: Implement UOLSGameplayAbility.
|
||||
// bool IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const;
|
||||
// void AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility);
|
||||
// void RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility);
|
||||
// void CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility);
|
||||
|
||||
// Uses a gameplay effect to add the specified dynamic granted tag.
|
||||
void AddDynamicTagGameplayEffect(const FGameplayTag& tag);
|
||||
|
||||
// Removes all active instances of the gameplay effect that was used to add the specified dynamic granted tag.
|
||||
void RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag);
|
||||
|
||||
/** Gets the ability target data associated with the given ability handle and activation info */
|
||||
void GetAbilityTargetData(const FGameplayAbilitySpecHandle abilityHandle, FGameplayAbilityActivationInfo activationInfo, FGameplayAbilityTargetDataHandle& outTargetDataHandle);
|
||||
|
||||
/** Sets the current tag relationship mapping, if null it will clear it out */
|
||||
void SetTagRelationshipMapping(class UOLSAbilityTagRelationshipMappingDataAsset* newMapping);
|
||||
|
||||
/** Looks at ability tags and gathers additional required and blocking tags */
|
||||
void GetAdditionalActivationTagRequirements(const FGameplayTagContainer& abilityTags, FGameplayTagContainer& outActivationRequired, FGameplayTagContainer& outActivationBlocked) const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "OLS Ability System", DisplayName = "Enable Ability Batch RPCs", meta = (AllowPrivateAccess = true))
|
||||
uint8 bShouldEnableBatchRPC : 1 = true;
|
||||
|
||||
protected:
|
||||
|
||||
// If set, this table is used to look up tag relationships for activate and cancel
|
||||
UPROPERTY()
|
||||
TObjectPtr<class UOLSAbilityTagRelationshipMappingDataAsset> TagRelationshipMapping = nullptr;
|
||||
|
||||
// Handles to abilities that had their input pressed this frame.
|
||||
TArray<FGameplayAbilitySpecHandle> InputPressedSpecHandles;
|
||||
|
||||
// Handles to abilities that had their input released this frame.
|
||||
TArray<FGameplayAbilitySpecHandle> InputReleasedSpecHandles;
|
||||
|
||||
// Handles to abilities that have their input held.
|
||||
TArray<FGameplayAbilitySpecHandle> InputHeldSpecHandles;
|
||||
};
|
||||
|
99
Source/ols/Public/Components/OLSPawnExtensionComponent.h
Normal file
99
Source/ols/Public/Components/OLSPawnExtensionComponent.h
Normal file
@ -0,0 +1,99 @@
|
||||
// © 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 "Components/GameFrameworkInitStateInterface.h"
|
||||
#include "Components/PawnComponent.h"
|
||||
#include "OLSPawnExtensionComponent.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogOLSPawnExtensionComponent, Verbose, All);
|
||||
|
||||
namespace EEndPlayReason { enum Type : int; }
|
||||
|
||||
/**
|
||||
* Component that adds functionality to all Pawn classes so it can be used for characters/vehicles/etc.
|
||||
* This coordinates the initialization of other components.
|
||||
*/
|
||||
UCLASS()
|
||||
class OLS_API UOLSPawnExtensionComponent : public UPawnComponent, public IGameFrameworkInitStateInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
// Sets default values for this component's properties
|
||||
UOLSPawnExtensionComponent(const FObjectInitializer& objectInitializer);
|
||||
|
||||
/** The name of this overall feature, this one depends on the other named component features */
|
||||
static const FName NAME_ActorFeatureName;
|
||||
|
||||
//~ 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
|
||||
|
||||
/** Returns the pawn extension component if one exists on the specified actor. */
|
||||
UFUNCTION(BlueprintPure, Category = "OLS|Pawn")
|
||||
static class UOLSPawnExtensionComponent* FindPawnExtensionComponent(const AActor* actor);
|
||||
|
||||
/** Gets the current ability system component, which may be owned by a different actor */
|
||||
UFUNCTION(BlueprintPure, Category = "OLS|Pawn")
|
||||
class UOLSAbilitySystemComponent* GetOLSAbilitySystemComponent() const ;
|
||||
|
||||
public:
|
||||
|
||||
/** Gets the pawn data, which is used to specify pawn properties in data */
|
||||
template <class T>
|
||||
const T* GetPawnData() const { return Cast<T>(PawnData); }
|
||||
|
||||
/** Sets the current pawn data */
|
||||
void SetPawnData(const class UOLSPawnDataAsset* pawnData);
|
||||
|
||||
/** Should be called by the owning pawn to become the avatar of the ability system. */
|
||||
void InitializeAbilitySystem(class UOLSAbilitySystemComponent* asc, AActor* ownerActor);
|
||||
|
||||
/** Should be called by the owning pawn to remove itself as the avatar of the ability system. */
|
||||
void UninitializeAbilitySystem();
|
||||
|
||||
/** Should be called by the owning pawn when the pawn's controller changes. */
|
||||
void HandleControllerChanged();
|
||||
|
||||
/** Should be called by the owning pawn when the player state has been replicated. */
|
||||
void HandlePlayerStateReplicated();
|
||||
|
||||
/** Should be called by the owning pawn when the input component is setup. */
|
||||
void SetupPlayerInputComponent();
|
||||
|
||||
/** Register with the OnAbilitySystemInitialized delegate and broadcast if our pawn has been registered with the ability system component */
|
||||
void OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate delegate);
|
||||
|
||||
/** Register with the OnAbilitySystemUninitialized delegate fired when our pawn is removed as the ability system's avatar actor */
|
||||
void OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate delegate);
|
||||
|
||||
protected:
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_PawnData();
|
||||
|
||||
protected:
|
||||
|
||||
/** Delegate fired when our pawn becomes the ability system's avatar actor */
|
||||
FSimpleMulticastDelegate OnAbilitySystemInitialized;
|
||||
|
||||
/** Delegate fired when our pawn is removed as the ability system's avatar actor */
|
||||
FSimpleMulticastDelegate OnAbilitySystemUninitialized;
|
||||
|
||||
protected:
|
||||
|
||||
/** Pawn data used to create the pawn. Specified from a spawn function or on a placed instance. */
|
||||
UPROPERTY(EditInstanceOnly, ReplicatedUsing = OnRep_PawnData, Category = "Lyra|Pawn")
|
||||
TObjectPtr<const class UOLSPawnDataAsset> PawnData = nullptr;
|
||||
|
||||
/** Pointer to the ability system component that is cached for convenience. */
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<class UOLSAbilitySystemComponent > AbilitySystemComponent = nullptr;
|
||||
};
|
Loading…
Reference in New Issue
Block a user