Files
PHY/Source/PHY/Private/Characters/PHYCharacterBase.cpp
2026-04-26 10:35:30 +08:00

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);
}