592 lines
16 KiB
C++
592 lines
16 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Characters/PHYCharacterBase.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYCharacterBase)
|
|
|
|
#include "AbilitySystemComponent.h"
|
|
#include "Animation/PHYCharacterMeshBridgeComponent.h"
|
|
#include "Camera/CameraComponent.h"
|
|
#include "Characters/PHYCharacterSettings.h"
|
|
#include "Characters/PHYCharacterStateComponent.h"
|
|
#include "Components/CapsuleComponent.h"
|
|
#include "Components/GameFrameworkComponentManager.h"
|
|
#include "Components/SkeletalMeshComponent.h"
|
|
#include "Feedback/GES_ContextEffectComponent.h"
|
|
#include "GCS_CombatSystemComponent.h"
|
|
#include "GGA_AbilitySystemComponent.h"
|
|
#include "GameFramework/CharacterMovementComponent.h"
|
|
#include "Interaction/GGS_InteractionSystemComponent.h"
|
|
#include "Net/UnrealNetwork.h"
|
|
#include "PHYGameplayTags.h"
|
|
#include "Ragdoll/GGS_RagdollComponent.h"
|
|
#include "Targeting/GCS_TargetingSystemComponent.h"
|
|
#include "Team/GCS_CombatTeamAgentComponent.h"
|
|
|
|
APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
bReplicates = true;
|
|
|
|
CharacterStateComponent = CreateDefaultSubobject<UPHYCharacterStateComponent>(TEXT("CharacterStateComponent"));
|
|
CombatSystemComponent = CreateDefaultSubobject<UGCS_CombatSystemComponent>(TEXT("CombatSystemComponent"));
|
|
TargetingSystemComponent = CreateDefaultSubobject<UGCS_TargetingSystemComponent>(TEXT("TargetingSystemComponent"));
|
|
CombatTeamAgentComponent = CreateDefaultSubobject<UGCS_CombatTeamAgentComponent>(TEXT("CombatTeamAgentComponent"));
|
|
InteractionSystemComponent = CreateDefaultSubobject<UGGS_InteractionSystemComponent>(TEXT("InteractionSystemComponent"));
|
|
RagdollComponent = CreateDefaultSubobject<UGGS_RagdollComponent>(TEXT("RagdollComponent"));
|
|
ContextEffectComponent = CreateDefaultSubobject<UGES_ContextEffectComponent>(TEXT("ContextEffectComponent"));
|
|
MeshBridgeComponent = CreateDefaultSubobject<UPHYCharacterMeshBridgeComponent>(TEXT("MeshBridgeComponent"));
|
|
DisplayMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("DisplayMeshComponent"));
|
|
DisplayMeshComponent->SetupAttachment(GetMesh());
|
|
DisplayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
|
DisplayMeshComponent->SetGenerateOverlapEvents(false);
|
|
}
|
|
|
|
void APHYCharacterBase::PreInitializeComponents()
|
|
{
|
|
Super::PreInitializeComponents();
|
|
|
|
UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
|
|
}
|
|
|
|
void APHYCharacterBase::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
ApplyCharacterSettings();
|
|
|
|
if (MeshBridgeComponent)
|
|
{
|
|
MeshBridgeComponent->InitializeMeshBridge(this, DisplayMeshComponent);
|
|
}
|
|
|
|
if (RagdollComponent)
|
|
{
|
|
RagdollComponent->SetMeshComponent(GetMesh());
|
|
}
|
|
|
|
if (ContextEffectComponent)
|
|
{
|
|
ContextEffectComponent->SetGameplayTagsProvider(this);
|
|
}
|
|
|
|
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady);
|
|
}
|
|
|
|
void APHYCharacterBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|
{
|
|
UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this);
|
|
|
|
Super::EndPlay(EndPlayReason);
|
|
}
|
|
|
|
void APHYCharacterBase::PossessedBy(AController* NewController)
|
|
{
|
|
Super::PossessedBy(NewController);
|
|
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementIntent(FVector::ZeroVector);
|
|
}
|
|
}
|
|
|
|
void APHYCharacterBase::OnRep_Controller()
|
|
{
|
|
Super::OnRep_Controller();
|
|
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementIntent(FVector::ZeroVector);
|
|
}
|
|
}
|
|
|
|
UAbilitySystemComponent* APHYCharacterBase::GetAbilitySystemComponent() const
|
|
{
|
|
return CachedAbilitySystemComponent;
|
|
}
|
|
|
|
void APHYCharacterBase::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
|
|
{
|
|
if (CachedAbilitySystemComponent)
|
|
{
|
|
CachedAbilitySystemComponent->GetOwnedGameplayTags(TagContainer);
|
|
}
|
|
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->GetOwnedStateTags(TagContainer);
|
|
}
|
|
}
|
|
|
|
void APHYCharacterBase::InitializeAbilitySystem(UAbilitySystemComponent* NewAbilitySystemComponent, AActor* OwnerActor)
|
|
{
|
|
if (!NewAbilitySystemComponent || !OwnerActor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (CachedAbilitySystemComponent == NewAbilitySystemComponent && bAbilitySystemReady)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CachedAbilitySystemComponent = NewAbilitySystemComponent;
|
|
|
|
if (UGGA_AbilitySystemComponent* GGAAbilitySystemComponent = Cast<UGGA_AbilitySystemComponent>(NewAbilitySystemComponent))
|
|
{
|
|
GGAAbilitySystemComponent->InitializeAbilitySystem(OwnerActor, this);
|
|
}
|
|
else
|
|
{
|
|
NewAbilitySystemComponent->InitAbilityActorInfo(OwnerActor, this);
|
|
}
|
|
|
|
bAbilitySystemReady = true;
|
|
}
|
|
|
|
void APHYCharacterBase::ClearAbilitySystem()
|
|
{
|
|
if (UGGA_AbilitySystemComponent* GGAAbilitySystemComponent = Cast<UGGA_AbilitySystemComponent>(CachedAbilitySystemComponent))
|
|
{
|
|
GGAAbilitySystemComponent->UninitializeAbilitySystem();
|
|
}
|
|
|
|
CachedAbilitySystemComponent = nullptr;
|
|
bAbilitySystemReady = false;
|
|
}
|
|
|
|
bool APHYCharacterBase::HandleInputTag(const FGameplayTag InputTag, const ETriggerEvent TriggerEvent)
|
|
{
|
|
if (!InputTag.IsValid() || IGCS_CombatEntityInterface::Execute_IsDead(this))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const bool bPressed = TriggerEvent == ETriggerEvent::Started || TriggerEvent == ETriggerEvent::Triggered;
|
|
const bool bReleased = TriggerEvent == ETriggerEvent::Completed || TriggerEvent == ETriggerEvent::Canceled;
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Jump)
|
|
{
|
|
if (bPressed)
|
|
{
|
|
Jump();
|
|
}
|
|
else if (bReleased)
|
|
{
|
|
StopJumping();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Sprint)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementState(bPressed ? PHYGameplayTags::State_Movement_Sprint : PHYGameplayTags::State_Movement_Run);
|
|
}
|
|
|
|
if (UCharacterMovementComponent* MoveComponent = GetCharacterMovement())
|
|
{
|
|
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
|
MoveComponent->MaxWalkSpeed = bPressed ? Settings->DefaultSprintSpeed : Settings->DefaultMaxWalkSpeed;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Aim)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementSet(bPressed ? PHYGameplayTags::State_MovementSet_Aiming : PHYGameplayTags::State_MovementSet_Default);
|
|
CharacterStateComponent->SetRotationMode(bPressed ? PHYGameplayTags::State_Rotation_Strafe : PHYGameplayTags::State_Rotation_OrientToMovement);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_LockOn && bPressed)
|
|
{
|
|
if (TargetingSystemComponent)
|
|
{
|
|
if (TargetingSystemComponent->GetTargetedActor())
|
|
{
|
|
SetCombatTargetActor(nullptr);
|
|
}
|
|
else
|
|
{
|
|
TargetingSystemComponent->SearchForActorToTarget();
|
|
SetCombatTargetActor(TargetingSystemComponent->GetTargetedActor());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Interact && bPressed)
|
|
{
|
|
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
|
return RequestInteraction(Settings->DefaultInteractionOption);
|
|
}
|
|
|
|
const FGameplayTag AbilityTag = GetAbilityTagForInputTag(InputTag);
|
|
if (AbilityTag.IsValid() && bPressed && CachedAbilitySystemComponent)
|
|
{
|
|
FGameplayTagContainer AbilityTags;
|
|
AbilityTags.AddTag(AbilityTag);
|
|
return CachedAbilitySystemComponent->TryActivateAbilitiesByTag(AbilityTags);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void APHYCharacterBase::SetMovementIntent(const FVector NewMovementIntent)
|
|
{
|
|
const FVector ClampedIntent = NewMovementIntent.GetClampedToMaxSize(1.0f);
|
|
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementIntent(ClampedIntent);
|
|
}
|
|
|
|
if (!HasAuthority())
|
|
{
|
|
ServerSetMovementIntent(ClampedIntent);
|
|
}
|
|
}
|
|
|
|
void APHYCharacterBase::SetCombatTargetActor(AActor* NewCombatTargetActor)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetCombatTargetActor(NewCombatTargetActor);
|
|
}
|
|
|
|
if (TargetingSystemComponent)
|
|
{
|
|
TargetingSystemComponent->SetTargetedActor(NewCombatTargetActor);
|
|
}
|
|
|
|
if (!HasAuthority())
|
|
{
|
|
ServerSetCombatTargetActor(NewCombatTargetActor);
|
|
}
|
|
}
|
|
|
|
bool APHYCharacterBase::RequestInteraction(const int32 OptionIndex)
|
|
{
|
|
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
|
if (!Settings->bEnableGenericGameInteraction || !InteractionSystemComponent)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!HasAuthority())
|
|
{
|
|
ServerRequestInteraction(OptionIndex);
|
|
return true;
|
|
}
|
|
|
|
InteractionSystemComponent->SearchInteractableActors();
|
|
InteractionSystemComponent->StartInteraction(OptionIndex);
|
|
return true;
|
|
}
|
|
|
|
bool APHYCharacterBase::RequestInstantInteraction(const int32 OptionIndex)
|
|
{
|
|
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
|
if (!Settings->bEnableGenericGameInteraction || !InteractionSystemComponent)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!HasAuthority())
|
|
{
|
|
ServerRequestInstantInteraction(OptionIndex);
|
|
return true;
|
|
}
|
|
|
|
InteractionSystemComponent->SearchInteractableActors();
|
|
InteractionSystemComponent->InstantInteraction(OptionIndex);
|
|
return true;
|
|
}
|
|
|
|
void APHYCharacterBase::EndInteraction()
|
|
{
|
|
if (!InteractionSystemComponent)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!HasAuthority())
|
|
{
|
|
ServerEndInteraction();
|
|
return;
|
|
}
|
|
|
|
InteractionSystemComponent->EndInteraction();
|
|
}
|
|
|
|
void APHYCharacterBase::CycleInteractionTarget(const bool bNext)
|
|
{
|
|
if (!InteractionSystemComponent)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!HasAuthority())
|
|
{
|
|
ServerCycleInteractionTarget(bNext);
|
|
return;
|
|
}
|
|
|
|
InteractionSystemComponent->CycleInteractableActors(bNext);
|
|
}
|
|
|
|
AActor* APHYCharacterBase::GetCombatTargetActor_Implementation() const
|
|
{
|
|
if (CharacterStateComponent && CharacterStateComponent->GetCombatTargetActor())
|
|
{
|
|
return CharacterStateComponent->GetCombatTargetActor();
|
|
}
|
|
|
|
return TargetingSystemComponent ? TargetingSystemComponent->GetTargetedActor() : nullptr;
|
|
}
|
|
|
|
const UDataTable* APHYCharacterBase::GetComboDefinitionTable_Implementation() const
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
USceneComponent* APHYCharacterBase::GetCombatTargetObject_Implementation() const
|
|
{
|
|
const AActor* TargetActor = IGCS_CombatEntityInterface::Execute_GetCombatTargetActor(this);
|
|
return TargetActor ? TargetActor->GetRootComponent() : nullptr;
|
|
}
|
|
|
|
bool APHYCharacterBase::QueryAbilityActions_Implementation(FGameplayTagContainer AbilityTags, FGameplayTagContainer SourceTags, FGameplayTagContainer TargetTags, TArray<FGCS_AbilityAction>& AbilityActions)
|
|
{
|
|
(void)AbilityTags;
|
|
(void)SourceTags;
|
|
(void)TargetTags;
|
|
AbilityActions.Reset();
|
|
return false;
|
|
}
|
|
|
|
bool APHYCharacterBase::QueryAbilityActionsByContext_Implementation(UObject* Context, FGameplayTagContainer AbilityTags, FGameplayTagContainer SourceTags, FGameplayTagContainer TargetTags, TArray<FGCS_AbilityAction>& AbilityActions)
|
|
{
|
|
(void)Context;
|
|
(void)AbilityTags;
|
|
(void)SourceTags;
|
|
(void)TargetTags;
|
|
AbilityActions.Reset();
|
|
return false;
|
|
}
|
|
|
|
UObject* APHYCharacterBase::QueryWeapon_Implementation(const FGameplayTagQuery& Query) const
|
|
{
|
|
UObject* Weapon = CharacterStateComponent ? CharacterStateComponent->GetCurrentWeapon() : nullptr;
|
|
if (!Weapon || Query.IsEmpty())
|
|
{
|
|
return Weapon;
|
|
}
|
|
|
|
if (const IGameplayTagAssetInterface* WeaponTagsProvider = Cast<IGameplayTagAssetInterface>(Weapon))
|
|
{
|
|
FGameplayTagContainer WeaponTags;
|
|
WeaponTagsProvider->GetOwnedGameplayTags(WeaponTags);
|
|
return Query.Matches(WeaponTags) ? Weapon : nullptr;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void APHYCharacterBase::SetRotationMode_Implementation(const FGameplayTag NewRotationMode)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetRotationMode(NewRotationMode);
|
|
}
|
|
}
|
|
|
|
FGameplayTag APHYCharacterBase::GetRotationMode_Implementation() const
|
|
{
|
|
return CharacterStateComponent ? CharacterStateComponent->GetRotationMode() : FGameplayTag();
|
|
}
|
|
|
|
void APHYCharacterBase::SetMovementSet_Implementation(const FGameplayTag NewMovementSet)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementSet(NewMovementSet);
|
|
}
|
|
}
|
|
|
|
FGameplayTag APHYCharacterBase::GetMovementSet_Implementation() const
|
|
{
|
|
return CharacterStateComponent ? CharacterStateComponent->GetMovementSet() : FGameplayTag();
|
|
}
|
|
|
|
void APHYCharacterBase::SetMovementState_Implementation(const FGameplayTag NewMovementState)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementState(NewMovementState);
|
|
}
|
|
}
|
|
|
|
FGameplayTag APHYCharacterBase::GetMovementState_Implementation() const
|
|
{
|
|
return CharacterStateComponent ? CharacterStateComponent->GetMovementState() : FGameplayTag();
|
|
}
|
|
|
|
void APHYCharacterBase::StartDeath_Implementation()
|
|
{
|
|
if (CharacterStateComponent && CharacterStateComponent->IsDead())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetDead(true);
|
|
}
|
|
|
|
if (CachedAbilitySystemComponent)
|
|
{
|
|
CachedAbilitySystemComponent->CancelAllAbilities();
|
|
}
|
|
|
|
if (UCharacterMovementComponent* MoveComponent = GetCharacterMovement())
|
|
{
|
|
MoveComponent->DisableMovement();
|
|
}
|
|
|
|
if (UCapsuleComponent* Capsule = GetCapsuleComponent())
|
|
{
|
|
Capsule->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
|
}
|
|
}
|
|
|
|
void APHYCharacterBase::FinishDeath_Implementation()
|
|
{
|
|
if (RagdollComponent && !RagdollComponent->IsRagdolling())
|
|
{
|
|
RagdollComponent->StartRagdoll();
|
|
}
|
|
}
|
|
|
|
bool APHYCharacterBase::IsDead_Implementation() const
|
|
{
|
|
return CharacterStateComponent && CharacterStateComponent->IsDead();
|
|
}
|
|
|
|
FVector APHYCharacterBase::GetMovementIntent_Implementation() const
|
|
{
|
|
return CharacterStateComponent ? CharacterStateComponent->GetMovementIntent() : FVector::ZeroVector;
|
|
}
|
|
|
|
UObject* APHYCharacterBase::GetCurrentWeapon_Implementation(UObject* Context) const
|
|
{
|
|
(void)Context;
|
|
return CharacterStateComponent ? CharacterStateComponent->GetCurrentWeapon() : nullptr;
|
|
}
|
|
|
|
void APHYCharacterBase::SetCurrentWeapon_Implementation(UObject* Weapon)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetCurrentWeapon(Weapon);
|
|
}
|
|
}
|
|
|
|
bool APHYCharacterBase::GetRelativeTransformToSocket_Implementation(const USkeletalMeshComponent* InSkeletalMeshComponent, const UStaticMesh* StaticMesh, const USkeletalMesh* SkeletalMesh, const FName SocketName, FTransform& OutTransform) const
|
|
{
|
|
(void)StaticMesh;
|
|
(void)SkeletalMesh;
|
|
|
|
if (!InSkeletalMeshComponent || SocketName.IsNone() || !InSkeletalMeshComponent->DoesSocketExist(SocketName))
|
|
{
|
|
OutTransform = FTransform::Identity;
|
|
return false;
|
|
}
|
|
|
|
OutTransform = InSkeletalMeshComponent->GetSocketTransform(SocketName, RTS_Component);
|
|
return true;
|
|
}
|
|
|
|
FGameplayTag APHYCharacterBase::GetAbilityTagForInputTag(const FGameplayTag InputTag) const
|
|
{
|
|
if (InputTag == PHYGameplayTags::Input_Attack_Primary)
|
|
{
|
|
return PHYGameplayTags::Ability_Attack_Primary;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Attack_Secondary)
|
|
{
|
|
return PHYGameplayTags::Ability_Attack_Secondary;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Jump)
|
|
{
|
|
return PHYGameplayTags::Ability_Jump;
|
|
}
|
|
|
|
if (InputTag == PHYGameplayTags::Input_Interact)
|
|
{
|
|
return PHYGameplayTags::Ability_Interact;
|
|
}
|
|
|
|
return FGameplayTag();
|
|
}
|
|
|
|
void APHYCharacterBase::ApplyCharacterSettings()
|
|
{
|
|
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
|
|
|
if (UCharacterMovementComponent* MoveComponent = GetCharacterMovement())
|
|
{
|
|
MoveComponent->MaxWalkSpeed = Settings->DefaultMaxWalkSpeed;
|
|
MoveComponent->MaxAcceleration = Settings->DefaultMaxAcceleration;
|
|
}
|
|
|
|
if (CharacterStateComponent && GetCharacterMovement() && GetCharacterMovement()->IsFalling())
|
|
{
|
|
CharacterStateComponent->SetMovementState(PHYGameplayTags::State_Movement_Falling);
|
|
}
|
|
}
|
|
|
|
void APHYCharacterBase::ServerSetMovementIntent_Implementation(const FVector NewMovementIntent)
|
|
{
|
|
if (CharacterStateComponent)
|
|
{
|
|
CharacterStateComponent->SetMovementIntent(NewMovementIntent);
|
|
}
|
|
}
|
|
|
|
void APHYCharacterBase::ServerSetCombatTargetActor_Implementation(AActor* NewCombatTargetActor)
|
|
{
|
|
SetCombatTargetActor(NewCombatTargetActor);
|
|
}
|
|
|
|
void APHYCharacterBase::ServerRequestInteraction_Implementation(const int32 OptionIndex)
|
|
{
|
|
RequestInteraction(OptionIndex);
|
|
}
|
|
|
|
void APHYCharacterBase::ServerRequestInstantInteraction_Implementation(const int32 OptionIndex)
|
|
{
|
|
RequestInstantInteraction(OptionIndex);
|
|
}
|
|
|
|
void APHYCharacterBase::ServerEndInteraction_Implementation()
|
|
{
|
|
EndInteraction();
|
|
}
|
|
|
|
void APHYCharacterBase::ServerCycleInteractionTarget_Implementation(const bool bNext)
|
|
{
|
|
CycleInteractionTarget(bNext);
|
|
}
|