Files
Cog/Source/CogSample/CogSampleCharacter.cpp
T
Eduardo Valencia 7543b49ef7 Updated to 5.3.x, renamed interface function, and more
In CogSampleSpawnPredictionComponent.cpp, lines 299 through 302 have return statements of FColor::FColor, these have been updated to a single FColor return statement
In CogSampleTargetableInterface.h, the GetTargetLocation function does not compile against Linux. Reason being that it interferes with built in functions that share the same name (notably within the AIController class). This has been changed to GetTargetActorLocation to maintain a similar name. Recommend adding comments when possible.

Additionaly, the sample project and the editor have had their IncludeOrderVersion updated to 5.2. This was done to clear the warning listing that 5.1 will be deprecated in the next major version release.

The project compiles against Windows and Linux (likely other platforms too, unable to check)
Happy to help! :)
2024-02-15 18:59:25 -05:00

875 lines
34 KiB
C++

#include "CogSampleCharacter.h"
#include "Camera/CameraComponent.h"
#include "CogCommon.h"
#include "CogSampleAbilitySystemComponent.h"
#include "CogSampleAttributeSet_Health.h"
#include "CogSampleAttributeSet_Misc.h"
#include "CogSampleCharacterMovementComponent.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "CogSampleFunctionLibrary_Team.h"
#include "CogSampleGameplayAbility.h"
#include "CogSampleLogCategories.h"
#include "CogSampleRootMotionParams.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "Engine/CollisionProfile.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/CheatManagerDefines.h"
#include "GameFramework/Controller.h"
#include "GameFramework/RootMotionSource.h"
#include "GameFramework/SpringArmComponent.h"
#include "Net/Core/PushModel/PushModel.h"
#include "Net/UnrealNetwork.h"
#if ENABLE_COG
#include "CogAbilityReplicator.h"
#include "CogDebugMetric.h"
#include "CogDebugPlot.h"
#endif //ENABLE_COG
//--------------------------------------------------------------------------------------------------------------------------
ACogSampleCharacter::ACogSampleCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UCogSampleCharacterMovementComponent>(ACharacter::CharacterMovementComponentName))
{
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...
GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f); // ...at this rotation rate
// Note: For faster iteration times these variables, and many more, can be tweaked in the Character Blueprint
// instead of recompiling to adjust them
GetCharacterMovement()->JumpZVelocity = 700.f;
GetCharacterMovement()->AirControl = 0.35f;
GetCharacterMovement()->MaxWalkSpeed = 500.f;
GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
// Create a camera boom (pulls in towards the player if there is a collision)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character
CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
// Create a follow camera
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
AbilitySystem = CreateDefaultSubobject<UCogSampleAbilitySystemComponent>(TEXT("AbilitySystem"));
AbilitySystem->SetIsReplicated(true);
AbilitySystem->SetReplicationMode(EGameplayEffectReplicationMode::Full);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
FDoRepLifetimeParams Params;
Params.bIsPushBased = true;
Params.Condition = COND_None;
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, Team, Params);
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, ProgressionLevel, Params);
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, Scale, Params);
Params.Condition = COND_OwnerOnly;
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, ActiveAbilityHandles, Params);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
InitializeAbilitySystem();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::BeginPlay()
{
Super::BeginPlay();
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
if (GetWorld()->GetNetMode() == NM_DedicatedServer)
{
GetMesh()->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
}
TryFinishInitialize();
RefreshServerAnimTickOption();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::MarkComponentsAsPendingKill()
{
Super::MarkComponentsAsPendingKill();
UnregisterFromAbilitySystemEvents();
}
//--------------------------------------------------------------------------------------------------------------------------
UAbilitySystemComponent* ACogSampleCharacter::GetAbilitySystemComponent() const
{
return AbilitySystem;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::PossessedBy(AController* NewController)
{
COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("Controller:%s"), *GetNameSafe(NewController));
if (InitialController == nullptr)
{
InitialController = NewController;
}
Super::PossessedBy(NewController);
if (bIsInitialized == false)
{
InitializeAbilitySystem();
}
else
{
//-------------------------------------------------------------------------------------------
// When possessing a NPC, we need to refresh the ability system actor info, so it knows about
// the new controller to be able to activate abilities.
//-------------------------------------------------------------------------------------------
AbilitySystem->InitAbilityActorInfo(this, this);
//-------------------------------------------------------------------------------------------
// We might be possessed when in a middle of an ability. Currently we prefer to cancel it.
//-------------------------------------------------------------------------------------------
AbilitySystem->CancelAllAbilities();
if (UCogSampleCharacterMovementComponent* MovementComp = Cast<UCogSampleCharacterMovementComponent>(GetMovementComponent()))
{
MovementComp->PossessedBy(NewController);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::UnPossessed()
{
COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT(""));
if (UCogSampleCharacterMovementComponent* MovementComp = Cast<UCogSampleCharacterMovementComponent>(GetMovementComponent()))
{
MovementComp->UnPossessed();
}
Super::UnPossessed();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::AcknowledgePossession(AController* NewController)
{
COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("Controller:%s - NewController:%s"), *GetNameSafe(NewController), *GetNameSafe(Controller));
//-------------------------------------------------------------------------------------------
// Set the controller otherwise when the player possesses a NPC, he would not be able to cast
// any ability. The ability system component needs to know the controller and therefore it
// needs to be set before calling InitAbilityActorInfo.
// See FGameplayAbilityActorInfo::InitFromActor
//-------------------------------------------------------------------------------------------
Controller = NewController;
if (AbilitySystem != nullptr)
{
AbilitySystem->InitAbilityActorInfo(this, this);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::AcknowledgeUnpossession()
{
COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("OldController:%s"), *GetNameSafe(Controller));
Controller = nullptr;
AbilitySystem->InitAbilityActorInfo(this, this);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::InitializeAbilitySystem()
{
if (bIsAbilitySystemInitialized)
{
return;
}
AbilitySystem->InitAbilityActorInfo(this, this);
if (AbilitySystem->IsOwnerActorAuthoritative())
{
for (const TSubclassOf<UAttributeSet>& AttributeSet : AttributeSets)
{
if (IsValid(AttributeSet) == false)
{
continue;
}
UAttributeSet* AttributeSetInstance = NewObject<UAttributeSet>(this, AttributeSet);
AbilitySystem->AddAttributeSetSubobject(AttributeSetInstance);
}
for (TSubclassOf<UGameplayEffect> Effect : Effects)
{
AbilitySystem->BP_ApplyGameplayEffectToSelf(Effect, 1, AbilitySystem->MakeEffectContext());
}
for (FPassiveAbilityInfo& AbilityInfo : PassiveAbilities)
{
const FGameplayAbilitySpec Spec(AbilityInfo.Ability, 1, INDEX_NONE, this);
AbilitySystem->GiveAbility(Spec);
}
for (int32 i = 0; i < ActiveAbilities.Num(); ++i)
{
const FActiveAbilityInfo& AbilityInfo = ActiveAbilities[i];
const FGameplayAbilitySpec Spec(AbilityInfo.Ability, 1, INDEX_NONE, this);
const FGameplayAbilitySpecHandle Handle = AbilitySystem->GiveAbility(Spec);
ActiveAbilityHandles.Add(Handle);
const FGameplayAbilitySpec* AddedSpec = AbilitySystem->FindAbilitySpecFromHandle(Handle);
if (AddedSpec == nullptr)
{
continue;
}
UCogSampleGameplayAbility* Ability = Cast<UCogSampleGameplayAbility>(AddedSpec->GetPrimaryInstance());
if (Ability == nullptr)
{
continue;
}
if (UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags.IsValidIndex(i) == false)
{
continue;
}
Ability->SetCooldownTag(UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags[i]);
}
UpdateActiveAbilitySlots();
MARK_PROPERTY_DIRTY_FROM_NAME(ACogSampleCharacter, ActiveAbilityHandles, this);
}
bIsAbilitySystemInitialized = true;
AbilitySystem->AddLooseGameplayTags(InitialTags);
TryFinishInitialize();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::RegisterToAbilitySystemEvents()
{
GameplayTagPropertyMap.Initialize(this, AbilitySystem);
//----------------------------------------
// Register to Tag change events
//----------------------------------------
GhostTagDelegateHandle = AbilitySystem->RegisterGameplayTagEvent(Tag_Status_Ghost, EGameplayTagEventType::NewOrRemoved).AddUObject(this, &ACogSampleCharacter::OnGhostTagNewOrRemoved);
//----------------------------------------
// Register to Attribute change events
//----------------------------------------
if (const UCogSampleAttributeSet_Misc* MiscAttributeSet = Cast<UCogSampleAttributeSet_Misc>(AbilitySystem->GetAttributeSet(UCogSampleAttributeSet_Misc::StaticClass())))
{
ScaleAttributeDelegateHandle = AbilitySystem->GetGameplayAttributeValueChangeDelegate(MiscAttributeSet->GetScaleAttribute()).AddUObject(this, &ACogSampleCharacter::OnScaleAttributeChanged);
}
//----------------------------------------
// Register to GameplayEffect events
//----------------------------------------
GameplayEffectAddedHandle = AbilitySystem->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(this, &ACogSampleCharacter::OnGameplayEffectAdded);
GameplayEffectRemovedHandle = AbilitySystem->OnAnyGameplayEffectRemovedDelegate().AddUObject(this, &ACogSampleCharacter::OnGameplayEffectRemoved);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::UnregisterFromAbilitySystemEvents()
{
//----------------------------------------
// Unregister to Attribute events
//----------------------------------------
if (const UCogSampleAttributeSet_Misc* MiscAttributeSet = Cast<UCogSampleAttributeSet_Misc>(AbilitySystem->GetAttributeSet(UCogSampleAttributeSet_Misc::StaticClass())))
{
AbilitySystem->GetGameplayAttributeValueChangeDelegate(MiscAttributeSet->GetScaleAttribute()).Remove(ScaleAttributeDelegateHandle);
}
//----------------------------------------
// Unregister to Tags events
//----------------------------------------
AbilitySystem->UnregisterGameplayTagEvent(GhostTagDelegateHandle, Tag_Status_Ghost, EGameplayTagEventType::NewOrRemoved);
//----------------------------------------
// Unregister to GameplayEffect events
//----------------------------------------
AbilitySystem->OnActiveGameplayEffectAddedDelegateToSelf.Remove(GameplayEffectAddedHandle);
AbilitySystem->OnAnyGameplayEffectRemovedDelegate().Remove(GameplayEffectRemovedHandle);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::TryFinishInitialize()
{
if (bIsInitialized)
{
return;
}
if (HasActorBegunPlay() == false)
{
return;
}
#if ENABLE_COG
ACogAbilityReplicator::TryApplyAllTweaksOnActor(this);
#endif //ENABLE_COG
RefreshScale();
RegisterToAbilitySystemEvents();
bIsInitialized = true;
OnInitialized.Broadcast(this);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ACogSampleCharacter::Move);
EnhancedInputComponent->BindAction(MoveZAction, ETriggerEvent::Triggered, this, &ACogSampleCharacter::MoveZ);
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ACogSampleCharacter::Look);
int32 AbilityIndex = 0;
for (const FActiveAbilityInfo& AbilityInfo : ActiveAbilities)
{
EnhancedInputComponent->BindAction(AbilityInfo.InputAction, ETriggerEvent::Started, this, &ACogSampleCharacter::OnAbilityInputStarted, AbilityIndex);
EnhancedInputComponent->BindAction(AbilityInfo.InputAction, ETriggerEvent::Completed, this, &ACogSampleCharacter::OnAbilityInputCompleted, AbilityIndex);
AbilityIndex++;
}
int32 ItemIndex = 0;
for (const UInputAction* ItemAction : ItemActions)
{
EnhancedInputComponent->BindAction(ItemAction, ETriggerEvent::Started, this, &ACogSampleCharacter::ActivateItem, ItemIndex);
ItemIndex++;
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnAbilityInputStarted(const FInputActionValue& Value, int32 Index)
{
COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index);
if (ActiveAbilityHandles.IsValidIndex(Index) == false)
{
return;
}
FGameplayAbilitySpecHandle Handle = ActiveAbilityHandles[Index];
FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(Handle);
if (Spec == nullptr)
{
return;
}
Spec->InputPressed = true;
//-----------------------------------------------------
// Replicate button press if ability is already active
//-----------------------------------------------------
if (Spec->IsActive())
{
const UGameplayAbility* AbilityToActivate = Spec->GetPrimaryInstance();
if (AbilityToActivate->bReplicateInputDirectly && AbilitySystem->IsOwnerActorAuthoritative() == false)
{
AbilitySystem->ServerSetInputPressed(Spec->Handle);
}
AbilitySystem->AbilitySpecInputPressed(*Spec);
AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec->Handle, Spec->ActivationInfo.GetActivationPredictionKey());
}
else
{
AbilitySystem->TryActivateAbility(Handle);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnAbilityInputCompleted(const FInputActionValue& Value, int32 Index)
{
COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index);
if (ActiveAbilityHandles.IsValidIndex(Index) == false)
{
return;
}
FGameplayAbilitySpecHandle Handle = ActiveAbilityHandles[Index];
FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(Handle);
if (Spec == nullptr)
{
return;
}
Spec->InputPressed = false;
UGameplayAbility* Ability= Spec->GetPrimaryInstance();
if (Ability == nullptr)
{
return;
}
if (Spec->IsActive() == false)
{
return;
}
if (Ability->bReplicateInputDirectly && AbilitySystem->IsOwnerActorAuthoritative() == false)
{
AbilitySystem->ServerSetInputReleased(Spec->Handle);
}
AbilitySystem->AbilitySpecInputReleased(*Spec);
AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec->Handle, Spec->ActivationInfo.GetActivationPredictionKey());
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::ActivateItem(const FInputActionValue& Value, int32 Index)
{
COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::Move(const FInputActionValue& Value)
{
FVector2D MoveInput2D = Value.Get<FVector2D>();
MoveInput.X = MoveInput2D.X;
MoveInput.Y = MoveInput2D.Y;
MoveInputInWorldSpace = MoveInput;
if (Controller != nullptr)
{
MoveInputInWorldSpace = TransformInputInWorldSpace(MoveInput);
AddMovementInput(MoveInputInWorldSpace);
}
}
//--------------------------------------------------------------------------------------------------------------------------
FVector ACogSampleCharacter::TransformInputInWorldSpace(const FVector& Input) const
{
if (Controller == nullptr)
{
return Input;
}
FRotator ControlRotation = Controller->GetControlRotation();
ControlRotation.Pitch = 0.0f;
ControlRotation.Roll = 0.0f;
FVector WorldInput = ControlRotation.RotateVector(FVector(Input.Y, Input.X, 0.0f));
return WorldInput;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::MoveZ(const FInputActionValue& Value)
{
const float ZInput = Value.Get<float>();
if (Controller != nullptr)
{
AddMovementInput(FVector::UpVector, ZInput);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::Look(const FInputActionValue& Value)
{
const FVector2D LookAxisVector = Value.Get<FVector2D>();
if (Controller != nullptr)
{
AddControllerYawInput(LookAxisVector.X);
AddControllerPitchInput(LookAxisVector.Y);
}
}
//--------------------------------------------------------------------------------------------------------------------------
ECogCommonAllegiance ACogSampleCharacter::GetAllegianceWithOtherActor(const AActor* OtherActor) const
{
const ECogCommonAllegiance Allegiance = static_cast<ECogCommonAllegiance>(UCogSampleFunctionLibrary_Team::GetActorsAllegiance(this, OtherActor));
return Allegiance;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::HandleDamageReceived(const FCogSampleDamageEventParams& Params)
{
OnDamageReceived.Broadcast(Params);
#if ENABLE_COG
FCogDebugMetric::AddMetric(this, "Damage Received", Params.MitigatedDamage, Params.UnmitigatedDamage, false);
#endif //ENABLE_COG
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::HandleDamageDealt(const FCogSampleDamageEventParams& Params)
{
OnDamageDealt.Broadcast(Params);
#if ENABLE_COG
FCogDebugMetric::AddMetric(this, "Damage Dealt", Params.MitigatedDamage, Params.UnmitigatedDamage, false);
#endif //ENABLE_COG
}
//--------------------------------------------------------------------------------------------------------------------------
bool ACogSampleCharacter::IsDead() const
{
return bIsDead;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnKilled(AActor* InInstigator, AActor* InCauser, const FGameplayEffectSpec& InEffectSpec, float InMagnitude)
{
bIsDead = true;
if (AbilitySystem != nullptr)
{
FGameplayEventData Payload;
Payload.EventTag = Tag_GameplayEvent_Killed;
Payload.Instigator = InInstigator;
Payload.Target = AbilitySystem->GetAvatarActor();
Payload.OptionalObject = InEffectSpec.Def;
Payload.ContextHandle = InEffectSpec.GetEffectContext();
Payload.InstigatorTags = *InEffectSpec.CapturedSourceTags.GetAggregatedTags();
Payload.TargetTags = *InEffectSpec.CapturedTargetTags.GetAggregatedTags();
Payload.EventMagnitude = InMagnitude;
FScopedPredictionWindow NewScopedWindow(AbilitySystem, true);
AbilitySystem->HandleGameplayEvent(Payload.EventTag, &Payload);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnRevived(AActor* InInstigator, AActor* InCauser, const FGameplayEffectSpec& InEffectSpec, float InMagnitude)
{
bIsDead = false;
if (AbilitySystem != nullptr)
{
FGameplayEventData Payload;
Payload.EventTag = Tag_GameplayEvent_Revived;
Payload.Instigator = InInstigator;
Payload.Target = AbilitySystem->GetAvatarActor();
Payload.OptionalObject = InEffectSpec.Def;
Payload.ContextHandle = InEffectSpec.GetEffectContext();
Payload.InstigatorTags = *InEffectSpec.CapturedSourceTags.GetAggregatedTags();
Payload.TargetTags = *InEffectSpec.CapturedTargetTags.GetAggregatedTags();
Payload.EventMagnitude = InMagnitude;
FScopedPredictionWindow NewScopedWindow(AbilitySystem, true);
AbilitySystem->HandleGameplayEvent(Payload.EventTag, &Payload);
}
}
// ----------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnGameplayEffectAdded(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& GameplayEffectSpec, FActiveGameplayEffectHandle Handle)
{
#if ENABLE_COG
FCogDebugPlot::PlotEvent(this, "Effects", GameplayEffectSpec.Def->GetFName(), GameplayEffectSpec.GetDuration() == 0.0f)
.AddParam("Name", AbilitySystemComponent->CleanupName(GetNameSafe(GameplayEffectSpec.Def)))
.AddParam("Effect Instigator", GetNameSafe(GameplayEffectSpec.GetEffectContext().GetInstigator()))
.AddParam("Effect Level", GameplayEffectSpec.GetLevel())
.AddParam("Effect Duration", GameplayEffectSpec.GetDuration());
#endif //ENABLE_COG
}
// ----------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnGameplayEffectRemoved(const FActiveGameplayEffect& RemovedGameplayEffect)
{
#if ENABLE_COG
FCogDebugPlot::PlotEventStop(this, "Effects", RemovedGameplayEffect.Spec.Def->GetFName());
#endif //ENABLE_COG
}
// ----------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnGhostTagNewOrRemoved(const FGameplayTag InTag, int32 NewCount)
{
#if UE_WITH_CHEAT_MANAGER
check(InTag == Tag_Status_Ghost);
bool bHasGhostTags = NewCount > 0;
if (bIsInGhostMode == bHasGhostTags)
{
return;
}
bIsInGhostMode = bHasGhostTags;
SetActorEnableCollision(bIsInGhostMode == false);
CameraBoom->bDoCollisionTest = bIsInGhostMode == false;
if (UCogSampleCharacterMovementComponent* MovementComponent = Cast<UCogSampleCharacterMovementComponent>(GetMovementComponent()))
{
MovementComponent->bCheatFlying = bIsInGhostMode;
MovementComponent->SetMovementMode(bIsInGhostMode ? MOVE_Flying : MOVE_Falling);
}
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
if (bIsInGhostMode)
{
Subsystem->AddMappingContext(GhostMappingContext, 0);
}
else
{
Subsystem->RemoveMappingContext(GhostMappingContext);
}
}
}
#endif //UE_WITH_CHEAT_MANAGER
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnScaleAttributeChanged(const FOnAttributeChangeData& Data)
{
RefreshScale();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::RefreshScale()
{
const float CurrentScaleValue = AbilitySystem->GetNumericAttribute(UCogSampleAttributeSet_Misc::GetScaleAttribute());
Scale = CurrentScaleValue;
MARK_PROPERTY_DIRTY_FROM_NAME(ACogSampleCharacter, Scale, this);
OnRep_Scale();
RefreshServerAnimTickOption();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::RefreshServerAnimTickOption()
{
const UCapsuleComponent* Capsule = GetCapsuleComponent();
if (Capsule == nullptr)
{
return;
}
USkeletalMeshComponent* SkeletalMesh = GetMesh();
if (SkeletalMesh == nullptr)
{
return;
}
const float ScaledHalfHeight = Capsule->GetScaledCapsuleHalfHeight();
const bool IsBigEnoughToSimulateBonesOnServer = ScaledHalfHeight > 200;
SkeletalMesh->VisibilityBasedAnimTickOption = IsBigEnoughToSimulateBonesOnServer ? EVisibilityBasedAnimTickOption::AlwaysTickPoseAndRefreshBones
: EVisibilityBasedAnimTickOption::OnlyTickMontagesWhenNotRendered;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnRep_Scale()
{
SetActorScale3D(FVector(Scale));
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::SetTeam(int32 Value)
{
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleCharacter, Team, Value, this);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::SetProgressionLevel(int32 Value)
{
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleCharacter, ProgressionLevel, Value, this);
}
//--------------------------------------------------------------------------------------------------------------------------
int32 ACogSampleCharacter::ApplyRootMotion(const FCogSampleRootMotionParams& Params)
{
if (HasAuthority() == false)
{
return (uint16)ERootMotionSourceID::Invalid;;
}
if (IsValid(Params.Effect))
{
FGameplayEffectContextHandle EffectContextHandle = AbilitySystem->MakeEffectContext();
EffectContextHandle.AddInstigator(Params.Instigator, Params.Causer);
FGameplayEffectSpecHandle SpecHandle = AbilitySystem->MakeOutgoingSpec(Params.Effect, 1.0f, EffectContextHandle);
SpecHandle.Data->SetDuration(Params.Duration, true);
if (SpecHandle.IsValid())
{
AbilitySystem->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get());
}
}
Client_ApplyRootMotion(Params);
int32 RootMotionSourceID = ApplyRootMotionShared(Params);
return RootMotionSourceID;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::Client_ApplyRootMotion_Implementation(const FCogSampleRootMotionParams& Params)
{
if (GetWorld()->GetNetMode() == NM_Client)
{
ApplyRootMotionShared(Params);
}
}
//--------------------------------------------------------------------------------------------------------------------------
uint16 ACogSampleCharacter::ApplyRootMotionShared(const FCogSampleRootMotionParams& Params)
{
UCogSampleCharacterMovementComponent* MovementComponent = Cast<UCogSampleCharacterMovementComponent>(GetMovementComponent());
if (MovementComponent == nullptr)
{
return (uint16)ERootMotionSourceID::Invalid;;
}
TSharedPtr<FRootMotionSource_JumpForce> JumpForce = MakeShared<FRootMotionSource_JumpForce>();
JumpForce->InstanceName = "ForceMove";
JumpForce->AccumulateMode = Params.IsAdditive ? ERootMotionAccumulateMode::Additive : ERootMotionAccumulateMode::Override;
JumpForce->Priority = (uint16)Params.Priority;
JumpForce->Duration = Params.Duration;
JumpForce->Rotation = Params.Rotation;
JumpForce->Distance = Params.Distance;
JumpForce->Height = Params.Height;
JumpForce->bDisableTimeout = Params.bFinishOnLanded; // If we finish on landed, we need to disable force's timeout
JumpForce->PathOffsetCurve = Params.PathOffsetCurve;
JumpForce->TimeMappingCurve = Params.TimeMappingCurve;
JumpForce->FinishVelocityParams.Mode = Params.FinishVelocityMode;
JumpForce->FinishVelocityParams.SetVelocity = Params.FinishSetVelocity;
JumpForce->FinishVelocityParams.ClampVelocity = Params.FinishClampVelocity;
uint16 RootMotionSourceID = MovementComponent->ApplyRootMotionSource(JumpForce);
return RootMotionSourceID;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnRep_ActiveAbilityHandles()
{
UpdateActiveAbilitySlots();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::UpdateActiveAbilitySlots()
{
for (int32 i = 0; i < ActiveAbilityHandles.Num(); ++i)
{
FGameplayAbilitySpecHandle& Handle = ActiveAbilityHandles[i];
if (UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags.IsValidIndex(i) == false)
{
return;
}
FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(Handle);
if (Spec == nullptr)
{
continue;
}
UCogSampleGameplayAbility* AbilityInstance = Cast<UCogSampleGameplayAbility>(Spec->GetPrimaryInstance());
if (AbilityInstance == nullptr)
{
continue;
}
FGameplayTag SlotTag = UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags[i];
AbilityInstance->SetCooldownTag(SlotTag);
}
}
//--------------------------------------------------------------------------------------------------------------------------
FVector ACogSampleCharacter::GetTargetActorLocation() const
{
return GetActorLocation();
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::GetTargetCapsules(TArray<const UCapsuleComponent*>& Capsules) const
{
Capsules.Add(GetCapsuleComponent());
}
//--------------------------------------------------------------------------------------------------------------------------
bool ACogSampleCharacter::GetMontage(FName MontageName, UAnimMontage*& Montage, bool bPrintWarning) const
{
Montage = nullptr;
if (MontageTable == nullptr)
{
return false;
}
static FString ContextString(TEXT("GetMontage"));
FCogSampleMontageTableRow* Row = MontageTable->FindRow<FCogSampleMontageTableRow>(MontageName, ContextString, bPrintWarning);
if (Row == nullptr)
{
return false;
}
Montage = Row->Montage;
return Montage != nullptr;
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::SetIsAiming(bool Value)
{
if (bIsAiming == Value)
{
return;
}
bIsAiming = Value;
OnAimingChanged.Broadcast(this, bIsAiming);
}