#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(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(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(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(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(Controller)) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(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(GetMovementComponent())) { MovementComp->PossessedBy(NewController); } } } //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleCharacter::UnPossessed() { COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("")); if (UCogSampleCharacterMovementComponent* MovementComp = Cast(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& AttributeSet : AttributeSets) { if (IsValid(AttributeSet) == false) { continue; } UAttributeSet* AttributeSetInstance = NewObject(this, AttributeSet); AbilitySystem->AddAttributeSetSubobject(AttributeSetInstance); } for (TSubclassOf 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(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(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(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(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 FCogDebugPlot::PlotEventStart(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 FCogDebugPlot::PlotEventStop(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(); 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(); if (Controller != nullptr) { AddMovementInput(FVector::UpVector, ZInput); } } //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleCharacter::Look(const FInputActionValue& Value) { const FVector2D LookAxisVector = Value.Get(); if (Controller != nullptr) { AddControllerYawInput(LookAxisVector.X); AddControllerPitchInput(LookAxisVector.Y); } } //-------------------------------------------------------------------------------------------------------------------------- ECogCommonAllegiance ACogSampleCharacter::GetAllegianceWithOtherActor(const AActor* OtherActor) const { const ECogCommonAllegiance Allegiance = static_cast(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(GetMovementComponent())) { MovementComponent->bCheatFlying = bIsInGhostMode; MovementComponent->SetMovementMode(bIsInGhostMode ? MOVE_Flying : MOVE_Falling); } if (APlayerController* PlayerController = Cast(Controller)) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(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(GetMovementComponent()); if (MovementComponent == nullptr) { return (uint16)ERootMotionSourceID::Invalid;; } TSharedPtr JumpForce = MakeShared(); 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(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& 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(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); }