Files
Cog/Source/CogSample/CogSampleGameplayAbility.cpp
T
2024-01-03 19:20:12 -05:00

282 lines
12 KiB
C++

#include "CogSampleGameplayAbility.h"
#include "CogSampleAttributeSet_Caster.h"
#include "CogSampleFunctionLibrary_Gameplay.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "CogSampleGameplayEffectContext.h"
#include "CogSampleLogCategories.h"
#include "CogSamplePlayerController.h"
#include "CogSampleSpawnPredictionComponent.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleGameplayAbility::UCogSampleGameplayAbility()
{
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
ActivationBlockedTags.AddTag(Tag_Status_Dead);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::PreActivate(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, FOnGameplayAbilityEnded::FDelegate* OnGameplayAbilityEndedDelegate, const FGameplayEventData* TriggerEventData)
{
COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("PreActivate"));
Super::PreActivate(Handle, ActorInfo, ActivationInfo, OnGameplayAbilityEndedDelegate, TriggerEventData);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("PredictionKey:%s"), *GetAbilitySystemComponentFromActorInfo_Checked()->ScopedPredictionKey.ToString());
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{
Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT(""));
}
//--------------------------------------------------------------------------------------------------------------------------
float UCogSampleGameplayAbility::GetUnmitigatedCooldownDuration_Implementation() const
{
return Cooldown.GetValueAtLevel(GetAbilityLevel());
}
//--------------------------------------------------------------------------------------------------------------------------
float UCogSampleGameplayAbility::GetUnmitigatedCost_Implementation() const
{
return Cost.GetValueAtLevel(GetAbilityLevel());
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSampleGameplayAbility::CheckCooldown(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, OUT FGameplayTagContainer* OptionalRelevantTags /*= nullptr*/) const
{
if (ActorInfo == nullptr)
{
return false;
}
if (ActorInfo->AbilitySystemComponent->HasMatchingGameplayTag(Tag_Status_NoCooldown))
{
return true;
}
if (Super::CheckCooldown(Handle, ActorInfo, OptionalRelevantTags))
{
return true;
}
if (OptionalRelevantTags != nullptr)
{
OptionalRelevantTags->AddTag(Tag_Ability_Activation_Fail_Cooldown);
}
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSampleGameplayAbility::CheckCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, OUT FGameplayTagContainer* OptionalRelevantTags /*= nullptr*/) const
{
if (ActorInfo == nullptr)
{
return false;
}
if (ActorInfo->AbilitySystemComponent->HasMatchingGameplayTag(Tag_Status_NoCost))
{
return true;
}
UGameplayEffect* CostEffect = GetCostGameplayEffect();
if (CostEffect != nullptr)
{
//-----------------------------------------------------------------------------------
// Can always start ability if cost == 0.
//-----------------------------------------------------------------------------------
if (IsCostGameplayEffectIsZero(CostEffect, GetAbilityLevel(Handle, ActorInfo), MakeEffectContext(Handle, ActorInfo)))
{
return true;
}
//-----------------------------------------------------------------------------------
// Can start ability if it cost stamina and stamina > 0
//-----------------------------------------------------------------------------------
if (CostEffect->InheritableGameplayEffectTags.CombinedTags.HasTag(Tag_Effect_Type_Cost_Stamina))
{
const float Stamina = ActorInfo->AbilitySystemComponent->GetNumericAttribute(UCogSampleAttributeSet_Caster::GetStaminaAttribute());
if (Stamina > 0)
{
return true;
}
}
}
//-----------------------------------------------------------------------------------
// Handle general case
//-----------------------------------------------------------------------------------
if (Super::CheckCost(Handle, ActorInfo, OptionalRelevantTags))
{
return true;
}
if (OptionalRelevantTags != nullptr)
{
OptionalRelevantTags->AddTag(Tag_Ability_Activation_Fail_Cost);
}
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
const FGameplayTagContainer* UCogSampleGameplayAbility::GetCooldownTags() const
{
FGameplayTagContainer* MutableTags = const_cast<FGameplayTagContainer*>(&CachedCooldownTags);
MutableTags->Reset();
const FGameplayTagContainer* ParentTags = Super::GetCooldownTags();
if (ParentTags)
{
MutableTags->AppendTags(*ParentTags);
}
MutableTags->AddTag(CooldownTag);
return MutableTags;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::ApplyCooldown(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const
{
if (ActorInfo->AbilitySystemComponent->HasMatchingGameplayTag(Tag_Status_NoCooldown))
{
return;
}
if (GetUnmitigatedCooldownDuration() <= 0.0f)
{
return;
}
if (UGameplayEffect* CooldownEffect = GetCooldownGameplayEffect())
{
FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(CooldownEffect->GetClass(), GetAbilityLevel());
SpecHandle.Data.Get()->DynamicGrantedTags.AddTag(CooldownTag);
ApplyGameplayEffectSpecToOwner(Handle, ActorInfo, ActivationInfo, SpecHandle);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const
{
if (ActorInfo->AbilitySystemComponent->HasMatchingGameplayTag(Tag_Status_NoCost))
{
return;
}
if (GetUnmitigatedCost() <= 0.0f)
{
return;
}
if (UGameplayEffect* CostEffect = GetCostGameplayEffect())
{
FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(CostEffect->GetClass(), GetAbilityLevel());
ApplyGameplayEffectSpecToOwner(Handle, ActorInfo, ActivationInfo, SpecHandle);
}
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSampleGameplayAbility::IsCostGameplayEffectIsZero(const UGameplayEffect* GameplayEffect, float Level, const FGameplayEffectContextHandle& EffectContext) const
{
FGameplayEffectSpec Spec(GameplayEffect, EffectContext, Level);
Spec.CalculateModifierMagnitudes();
for (int32 ModIdx = 0; ModIdx < Spec.Modifiers.Num(); ++ModIdx)
{
const FGameplayModifierInfo& ModDef = Spec.Def->Modifiers[ModIdx];
const FModifierSpec& ModSpec = Spec.Modifiers[ModIdx];
const float CostValue = ModSpec.GetEvaluatedMagnitude();
//----------------------------------------------------------------------------------------------
// The Cost in the Data is positive, but UCogSampleModifierCalculation_Cost negates it.
// Therefore, a cost less than zero is an actual cost, and a cost of 0 or greater can be ignored
//----------------------------------------------------------------------------------------------
if (CostValue < 0)
{
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
float UCogSampleGameplayAbility::GetFloatValueAtAbilityLevel(const FScalableFloat& ScalableFloat) const
{
return UCogSampleFunctionLibrary_Gameplay::GetFloatValue(ScalableFloat, GetAbilityLevel());
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSampleGameplayAbility::GetBoolValueAtAbilityLevel(const FScalableFloat& ScalableFloat) const
{
return UCogSampleFunctionLibrary_Gameplay::GetBoolValue(ScalableFloat, GetAbilityLevel());
}
//--------------------------------------------------------------------------------------------------------------------------
int32 UCogSampleGameplayAbility::GetIntValueAtAbilityLevel(const FScalableFloat& ScalableFloat) const
{
return UCogSampleFunctionLibrary_Gameplay::GetIntValue(ScalableFloat, GetAbilityLevel());
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::GetCooldownInfos(float& TimeRemaining, float& CooldownDuration) const
{
//-------------------------------------------------------------------------------------
// Provide a default Handle as it is not used in GetCooldownTimeRemainingAndDuration
//-------------------------------------------------------------------------------------
FGameplayAbilitySpecHandle Handle;
GetCooldownTimeRemainingAndDuration(Handle, CurrentActorInfo, TimeRemaining, CooldownDuration);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::SetupSpawnPrediction(AActor* Actor, int32 InstanceIndex)
{
if (Actor == nullptr)
{
return;
}
UCogSampleSpawnPredictionComponent* SpawnPrediction = Actor->FindComponentByClass<UCogSampleSpawnPredictionComponent>();
if (SpawnPrediction == nullptr)
{
return;
}
SetupSpawnPredictionComponent(SpawnPrediction, InstanceIndex);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::SetupSpawnPredictionComponent(UCogSampleSpawnPredictionComponent* SpawnPrediction, int32 InstanceIndex)
{
if (SpawnPrediction == nullptr)
{
return;
}
SpawnPrediction->SetCreator(CurrentActorInfo->AvatarActor.Get());
FCogSampleSpawnPredictionKey PredictedActorKey = FCogSampleSpawnPredictionKey::MakeFromAbility(*this, InstanceIndex);
SpawnPrediction->SetSpawnPredictionKey(PredictedActorKey);
if (GetCurrentActorInfo()->IsNetAuthority())
{
SpawnPrediction->SetRole(ECogSampleSpawnPredictionRole::Server);
}
else
{
SpawnPrediction->SetRole(ECogSampleSpawnPredictionRole::Predicted);
if (ACogSamplePlayerController* PlayerController = Cast<ACogSamplePlayerController>(GetCurrentActorInfo()->PlayerController))
{
PlayerController->SpawnPredictions.Add(SpawnPrediction);
}
}
}