Files
Cog/Source/CogSample/CogSampleCharacter.cpp
T
Arnaud Jamin 6d9494b685 Major Change - Rework how Cog gets integrated
Cog integration has been reworked to make it easier,  to keep Cog available between level loadings, and to properly tick ImGui while the game is paused.
Cog 's WindowManager is now a GameInstanceSubsystem.
The WindowManager ticks ImGui and the windows during the OnWorldPostActorTick delegate.
(If this is not working for your project, don't hesitate to open an issue.)

Check the readme to see how to integrate Cog.

The Plot debug functions (displayed by the Engine/Plot window) have been reworked as they were not properly working in Multi PIE in Single Process.

API changes:
- use FCogDebug::Plot instead of FCogDebugPlot::PlotValue
- use FCogDebug::InstantEvent  instead of FCogDebugPlot::PlotEventInstant
- use FCogDebug::StartEvent instead of FCogDebugPlot::PlotEventStart
- use FCogDebug::StopEvent instead of FCogDebugPlot::PlotEventStop
2025-02-11 13:29:12 -05:00

908 lines
35 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 "CogDebug.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);
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);
GhostTagDelegateHandle = AbilitySystem->RegisterGameplayTagEvent(Tag_Status_Invisible, EGameplayTagEventType::NewOrRemoved).AddUObject(this, &ACogSampleCharacter::OnInvisibleTagNewOrRemoved);
//----------------------------------------
// 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);
AbilitySystem->UnregisterGameplayTagEvent(GhostTagDelegateHandle, Tag_Status_Invisible, 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->BindActionValueLambda(AbilityInfo.InputAction, ETriggerEvent::Started,
[this, &AbilityInfo, AbilityIndex](const FInputActionValue& InputActionValue)
{
OnAbilityInputStarted(AbilityInfo.InputAction, InputActionValue, AbilityIndex);
});
EnhancedInputComponent->BindActionValueLambda(AbilityInfo.InputAction, ETriggerEvent::Completed,
[this, &AbilityInfo, AbilityIndex](const FInputActionValue& InputActionValue)
{
OnAbilityInputCompleted(AbilityInfo.InputAction, InputActionValue, AbilityIndex);
});
AbilityIndex++;
}
int32 ItemIndex = 0;
for (const UInputAction* ItemAction : ItemActions)
{
EnhancedInputComponent->BindAction(ItemAction, ETriggerEvent::Started, this, &ACogSampleCharacter::ActivateItem, ItemIndex);
ItemIndex++;
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnAbilityInputStarted(const UInputAction* InputAction, const FInputActionValue& Value, int32 Index)
{
COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index);
#if ENABLE_COG
FCogDebug::StartEvent(this, "Input", InputAction->GetFName());
#endif
if (ActiveAbilityHandles.IsValidIndex(Index) == false)
{
return;
}
FGameplayAbilitySpecHandle Handle = ActiveAbilityHandles[Index];
FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(Handle);
if (Spec == nullptr)
{
return;
}
Spec->InputPressed = true;
UGameplayAbility* Ability = Spec->GetPrimaryInstance();
if (Ability == nullptr)
{
return;
}
//-----------------------------------------------------
// 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, Ability->GetCurrentActivationInfo().GetActivationPredictionKey());
}
else
{
AbilitySystem->TryActivateAbility(Handle);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogSampleCharacter::OnAbilityInputCompleted(const UInputAction* InputAction, const FInputActionValue& Value, int32 Index)
{
COG_LOG_OBJECT(LogCogInput, ELogVerbosity::Verbose, this, TEXT("%d"), Index);
#if ENABLE_COG
FCogDebug::StopEvent(this, "Input", InputAction->GetFName());
#endif
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, Ability->GetCurrentActivationInfo().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
FCogDebug::StartEvent(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
FCogDebug::StopEvent(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::OnInvisibleTagNewOrRemoved(const FGameplayTag InTag, int32 NewCount)
{
#if UE_WITH_CHEAT_MANAGER
check(InTag == Tag_Status_Invisible);
bool bHasInvisibleTags = NewCount > 0;
SetActorHiddenInGame(bHasInvisibleTags);
#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);
}