2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LyraCharacter.h"
2022-09-13 07:18:28 +00:00
# include "AI/Navigation/NavigationTypes.h"
# include "AbilitySystem/LyraAbilitySystemComponent.h"
# include "AbilitySystemComponent.h"
# include "Camera/LyraCameraComponent.h"
# include "Character/LyraHealthComponent.h"
2022-05-23 18:41:30 +00:00
# include "Character/LyraPawnExtensionComponent.h"
# include "Components/CapsuleComponent.h"
# include "Components/SkeletalMeshComponent.h"
2022-09-13 07:18:28 +00:00
# include "Containers/EnumAsByte.h"
# include "Containers/Map.h"
# include "Containers/UnrealString.h"
# include "Delegates/Delegate.h"
# include "Engine/EngineBaseTypes.h"
# include "Engine/World.h"
# include "GameFramework/Character.h"
# include "GameFramework/CharacterMovementComponent.h"
# include "GameFramework/Controller.h"
# include "GameplayTagContainer.h"
# include "Logging/LogCategory.h"
# include "Logging/LogMacros.h"
# include "LyraCharacterMovementComponent.h"
# include "LyraGameplayTags.h"
# include "LyraLogChannels.h"
# include "Math/Rotator.h"
# include "Math/UnrealMathSSE.h"
# include "Math/Vector.h"
# include "Misc/AssertionMacros.h"
# include "Net/UnrealNetwork.h"
2022-05-23 18:41:30 +00:00
# include "Player/LyraPlayerController.h"
# include "Player/LyraPlayerState.h"
2022-09-13 07:18:28 +00:00
# include "SignificanceManager.h"
2022-05-23 18:41:30 +00:00
# include "System/LyraSignificanceManager.h"
2022-09-13 07:18:28 +00:00
# include "Templates/Casts.h"
2022-05-23 18:41:30 +00:00
# include "TimerManager.h"
2022-09-13 07:18:28 +00:00
# include "Trace/Detail/Channel.h"
# include "UObject/CoreNetTypes.h"
# include "UObject/NameTypes.h"
# include "UObject/Object.h"
# include "UObject/ObjectPtr.h"
# include "UObject/UObjectBaseUtility.h"
class AActor ;
class FLifetimeProperty ;
class IRepChangedPropertyTracker ;
class UInputComponent ;
2022-05-23 18:41:30 +00:00
static FName NAME_LyraCharacterCollisionProfile_Capsule ( TEXT ( " LyraPawnCapsule " ) ) ;
static FName NAME_LyraCharacterCollisionProfile_Mesh ( TEXT ( " LyraPawnMesh " ) ) ;
ALyraCharacter : : ALyraCharacter ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer . SetDefaultSubobjectClass < ULyraCharacterMovementComponent > ( ACharacter : : CharacterMovementComponentName ) )
{
// Avoid ticking characters if possible.
PrimaryActorTick . bCanEverTick = false ;
PrimaryActorTick . bStartWithTickEnabled = false ;
NetCullDistanceSquared = 900000000.0f ;
UCapsuleComponent * CapsuleComp = GetCapsuleComponent ( ) ;
check ( CapsuleComp ) ;
CapsuleComp - > InitCapsuleSize ( 40.0f , 90.0f ) ;
CapsuleComp - > SetCollisionProfileName ( NAME_LyraCharacterCollisionProfile_Capsule ) ;
USkeletalMeshComponent * MeshComp = GetMesh ( ) ;
check ( MeshComp ) ;
MeshComp - > SetRelativeRotation ( FRotator ( 0.0f , - 90.0f , 0.0f ) ) ; // Rotate mesh to be X forward since it is exported as Y forward.
MeshComp - > SetCollisionProfileName ( NAME_LyraCharacterCollisionProfile_Mesh ) ;
ULyraCharacterMovementComponent * LyraMoveComp = CastChecked < ULyraCharacterMovementComponent > ( GetCharacterMovement ( ) ) ;
LyraMoveComp - > GravityScale = 1.0f ;
LyraMoveComp - > MaxAcceleration = 2400.0f ;
LyraMoveComp - > BrakingFrictionFactor = 1.0f ;
LyraMoveComp - > BrakingFriction = 6.0f ;
LyraMoveComp - > GroundFriction = 8.0f ;
LyraMoveComp - > BrakingDecelerationWalking = 1400.0f ;
LyraMoveComp - > bUseControllerDesiredRotation = false ;
LyraMoveComp - > bOrientRotationToMovement = false ;
LyraMoveComp - > RotationRate = FRotator ( 0.0f , 720.0f , 0.0f ) ;
LyraMoveComp - > bAllowPhysicsRotationDuringAnimRootMotion = false ;
LyraMoveComp - > GetNavAgentPropertiesRef ( ) . bCanCrouch = true ;
LyraMoveComp - > bCanWalkOffLedgesWhenCrouching = true ;
LyraMoveComp - > SetCrouchedHalfHeight ( 65.0f ) ;
PawnExtComponent = CreateDefaultSubobject < ULyraPawnExtensionComponent > ( TEXT ( " PawnExtensionComponent " ) ) ;
PawnExtComponent - > OnAbilitySystemInitialized_RegisterAndCall ( FSimpleMulticastDelegate : : FDelegate : : CreateUObject ( this , & ThisClass : : OnAbilitySystemInitialized ) ) ;
PawnExtComponent - > OnAbilitySystemUninitialized_Register ( FSimpleMulticastDelegate : : FDelegate : : CreateUObject ( this , & ThisClass : : OnAbilitySystemUninitialized ) ) ;
HealthComponent = CreateDefaultSubobject < ULyraHealthComponent > ( TEXT ( " HealthComponent " ) ) ;
HealthComponent - > OnDeathStarted . AddDynamic ( this , & ThisClass : : OnDeathStarted ) ;
HealthComponent - > OnDeathFinished . AddDynamic ( this , & ThisClass : : OnDeathFinished ) ;
CameraComponent = CreateDefaultSubobject < ULyraCameraComponent > ( TEXT ( " CameraComponent " ) ) ;
CameraComponent - > SetRelativeLocation ( FVector ( - 300.0f , 0.0f , 75.0f ) ) ;
bUseControllerRotationPitch = false ;
bUseControllerRotationYaw = true ;
bUseControllerRotationRoll = false ;
BaseEyeHeight = 80.0f ;
CrouchedEyeHeight = 50.0f ;
}
void ALyraCharacter : : PreInitializeComponents ( )
{
Super : : PreInitializeComponents ( ) ;
}
void ALyraCharacter : : BeginPlay ( )
{
Super : : BeginPlay ( ) ;
UWorld * World = GetWorld ( ) ;
const bool bRegisterWithSignificanceManager = ! IsNetMode ( NM_DedicatedServer ) ;
if ( bRegisterWithSignificanceManager )
{
if ( ULyraSignificanceManager * SignificanceManager = USignificanceManager : : Get < ULyraSignificanceManager > ( World ) )
{
//@TODO: SignificanceManager->RegisterObject(this, (EFortSignificanceType)SignificanceType);
}
}
}
void ALyraCharacter : : EndPlay ( const EEndPlayReason : : Type EndPlayReason )
{
Super : : EndPlay ( EndPlayReason ) ;
UWorld * World = GetWorld ( ) ;
const bool bRegisterWithSignificanceManager = ! IsNetMode ( NM_DedicatedServer ) ;
if ( bRegisterWithSignificanceManager )
{
if ( ULyraSignificanceManager * SignificanceManager = USignificanceManager : : Get < ULyraSignificanceManager > ( World ) )
{
SignificanceManager - > UnregisterObject ( this ) ;
}
}
}
void ALyraCharacter : : Reset ( )
{
DisableMovementAndCollision ( ) ;
K2_OnReset ( ) ;
UninitAndDestroy ( ) ;
}
void ALyraCharacter : : GetLifetimeReplicatedProps ( TArray < FLifetimeProperty > & OutLifetimeProps ) const
{
Super : : GetLifetimeReplicatedProps ( OutLifetimeProps ) ;
DOREPLIFETIME_CONDITION ( ThisClass , ReplicatedAcceleration , COND_SimulatedOnly ) ;
DOREPLIFETIME ( ThisClass , MyTeamID )
}
void ALyraCharacter : : PreReplication ( IRepChangedPropertyTracker & ChangedPropertyTracker )
{
Super : : PreReplication ( ChangedPropertyTracker ) ;
if ( UCharacterMovementComponent * MovementComponent = GetCharacterMovement ( ) )
{
// Compress Acceleration: XY components as direction + magnitude, Z component as direct value
const double MaxAccel = MovementComponent - > MaxAcceleration ;
const FVector CurrentAccel = MovementComponent - > GetCurrentAcceleration ( ) ;
double AccelXYRadians , AccelXYMagnitude ;
FMath : : CartesianToPolar ( CurrentAccel . X , CurrentAccel . Y , AccelXYMagnitude , AccelXYRadians ) ;
ReplicatedAcceleration . AccelXYRadians = FMath : : FloorToInt ( ( AccelXYRadians / TWO_PI ) * 255.0 ) ; // [0, 2PI] -> [0, 255]
ReplicatedAcceleration . AccelXYMagnitude = FMath : : FloorToInt ( ( AccelXYMagnitude / MaxAccel ) * 255.0 ) ; // [0, MaxAccel] -> [0, 255]
ReplicatedAcceleration . AccelZ = FMath : : FloorToInt ( ( CurrentAccel . Z / MaxAccel ) * 127.0 ) ; // [-MaxAccel, MaxAccel] -> [-127, 127]
}
}
void ALyraCharacter : : NotifyControllerChanged ( )
{
const FGenericTeamId OldTeamId = GetGenericTeamId ( ) ;
Super : : NotifyControllerChanged ( ) ;
// Update our team ID based on the controller
if ( HasAuthority ( ) & & ( Controller ! = nullptr ) )
{
if ( ILyraTeamAgentInterface * ControllerWithTeam = Cast < ILyraTeamAgentInterface > ( Controller ) )
{
MyTeamID = ControllerWithTeam - > GetGenericTeamId ( ) ;
ConditionalBroadcastTeamChanged ( this , OldTeamId , MyTeamID ) ;
}
}
}
ALyraPlayerController * ALyraCharacter : : GetLyraPlayerController ( ) const
{
return CastChecked < ALyraPlayerController > ( Controller , ECastCheckedType : : NullAllowed ) ;
}
ALyraPlayerState * ALyraCharacter : : GetLyraPlayerState ( ) const
{
return CastChecked < ALyraPlayerState > ( GetPlayerState ( ) , ECastCheckedType : : NullAllowed ) ;
}
ULyraAbilitySystemComponent * ALyraCharacter : : GetLyraAbilitySystemComponent ( ) const
{
return Cast < ULyraAbilitySystemComponent > ( GetAbilitySystemComponent ( ) ) ;
}
UAbilitySystemComponent * ALyraCharacter : : GetAbilitySystemComponent ( ) const
{
return PawnExtComponent - > GetLyraAbilitySystemComponent ( ) ;
}
void ALyraCharacter : : OnAbilitySystemInitialized ( )
{
ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) ;
check ( LyraASC ) ;
HealthComponent - > InitializeWithAbilitySystem ( LyraASC ) ;
InitializeGameplayTags ( ) ;
}
void ALyraCharacter : : OnAbilitySystemUninitialized ( )
{
HealthComponent - > UninitializeFromAbilitySystem ( ) ;
}
void ALyraCharacter : : PossessedBy ( AController * NewController )
{
const FGenericTeamId OldTeamID = MyTeamID ;
Super : : PossessedBy ( NewController ) ;
PawnExtComponent - > HandleControllerChanged ( ) ;
// Grab the current team ID and listen for future changes
if ( ILyraTeamAgentInterface * ControllerAsTeamProvider = Cast < ILyraTeamAgentInterface > ( NewController ) )
{
MyTeamID = ControllerAsTeamProvider - > GetGenericTeamId ( ) ;
ControllerAsTeamProvider - > GetTeamChangedDelegateChecked ( ) . AddDynamic ( this , & ThisClass : : OnControllerChangedTeam ) ;
}
ConditionalBroadcastTeamChanged ( this , OldTeamID , MyTeamID ) ;
}
void ALyraCharacter : : UnPossessed ( )
{
AController * const OldController = Controller ;
// Stop listening for changes from the old controller
const FGenericTeamId OldTeamID = MyTeamID ;
if ( ILyraTeamAgentInterface * ControllerAsTeamProvider = Cast < ILyraTeamAgentInterface > ( OldController ) )
{
ControllerAsTeamProvider - > GetTeamChangedDelegateChecked ( ) . RemoveAll ( this ) ;
}
Super : : UnPossessed ( ) ;
PawnExtComponent - > HandleControllerChanged ( ) ;
// Determine what the new team ID should be afterwards
MyTeamID = DetermineNewTeamAfterPossessionEnds ( OldTeamID ) ;
ConditionalBroadcastTeamChanged ( this , OldTeamID , MyTeamID ) ;
}
void ALyraCharacter : : OnRep_Controller ( )
{
Super : : OnRep_Controller ( ) ;
PawnExtComponent - > HandleControllerChanged ( ) ;
}
void ALyraCharacter : : OnRep_PlayerState ( )
{
Super : : OnRep_PlayerState ( ) ;
PawnExtComponent - > HandlePlayerStateReplicated ( ) ;
}
void ALyraCharacter : : SetupPlayerInputComponent ( UInputComponent * PlayerInputComponent )
{
Super : : SetupPlayerInputComponent ( PlayerInputComponent ) ;
PawnExtComponent - > SetupPlayerInputComponent ( ) ;
}
void ALyraCharacter : : InitializeGameplayTags ( )
{
// Clear tags that may be lingering on the ability system from the previous pawn.
if ( ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
const FLyraGameplayTags & GameplayTags = FLyraGameplayTags : : Get ( ) ;
for ( const TPair < uint8 , FGameplayTag > & TagMapping : GameplayTags . MovementModeTagMap )
{
if ( TagMapping . Value . IsValid ( ) )
{
LyraASC - > SetLooseGameplayTagCount ( TagMapping . Value , 0 ) ;
}
}
for ( const TPair < uint8 , FGameplayTag > & TagMapping : GameplayTags . CustomMovementModeTagMap )
{
if ( TagMapping . Value . IsValid ( ) )
{
LyraASC - > SetLooseGameplayTagCount ( TagMapping . Value , 0 ) ;
}
}
ULyraCharacterMovementComponent * LyraMoveComp = CastChecked < ULyraCharacterMovementComponent > ( GetCharacterMovement ( ) ) ;
SetMovementModeTag ( LyraMoveComp - > MovementMode , LyraMoveComp - > CustomMovementMode , true ) ;
}
}
void ALyraCharacter : : GetOwnedGameplayTags ( FGameplayTagContainer & TagContainer ) const
{
if ( const ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
LyraASC - > GetOwnedGameplayTags ( TagContainer ) ;
}
}
bool ALyraCharacter : : HasMatchingGameplayTag ( FGameplayTag TagToCheck ) const
{
if ( const ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
return LyraASC - > HasMatchingGameplayTag ( TagToCheck ) ;
}
return false ;
}
bool ALyraCharacter : : HasAllMatchingGameplayTags ( const FGameplayTagContainer & TagContainer ) const
{
if ( const ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
return LyraASC - > HasAllMatchingGameplayTags ( TagContainer ) ;
}
return false ;
}
bool ALyraCharacter : : HasAnyMatchingGameplayTags ( const FGameplayTagContainer & TagContainer ) const
{
if ( const ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
return LyraASC - > HasAnyMatchingGameplayTags ( TagContainer ) ;
}
return false ;
}
void ALyraCharacter : : FellOutOfWorld ( const class UDamageType & dmgType )
{
HealthComponent - > DamageSelfDestruct ( /*bFellOutOfWorld=*/ true ) ;
}
void ALyraCharacter : : OnDeathStarted ( AActor * )
{
DisableMovementAndCollision ( ) ;
}
void ALyraCharacter : : OnDeathFinished ( AActor * )
{
GetWorld ( ) - > GetTimerManager ( ) . SetTimerForNextTick ( this , & ThisClass : : DestroyDueToDeath ) ;
}
void ALyraCharacter : : DisableMovementAndCollision ( )
{
if ( Controller )
{
Controller - > SetIgnoreMoveInput ( true ) ;
}
UCapsuleComponent * CapsuleComp = GetCapsuleComponent ( ) ;
check ( CapsuleComp ) ;
CapsuleComp - > SetCollisionEnabled ( ECollisionEnabled : : NoCollision ) ;
CapsuleComp - > SetCollisionResponseToAllChannels ( ECR_Ignore ) ;
ULyraCharacterMovementComponent * LyraMoveComp = CastChecked < ULyraCharacterMovementComponent > ( GetCharacterMovement ( ) ) ;
LyraMoveComp - > StopMovementImmediately ( ) ;
LyraMoveComp - > DisableMovement ( ) ;
}
void ALyraCharacter : : DestroyDueToDeath ( )
{
K2_OnDeathFinished ( ) ;
UninitAndDestroy ( ) ;
}
void ALyraCharacter : : UninitAndDestroy ( )
{
if ( GetLocalRole ( ) = = ROLE_Authority )
{
DetachFromControllerPendingDestroy ( ) ;
SetLifeSpan ( 0.1f ) ;
}
// Uninitialize the ASC if we're still the avatar actor (otherwise another pawn already did it when they became the avatar actor)
if ( ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
if ( LyraASC - > GetAvatarActor ( ) = = this )
{
PawnExtComponent - > UninitializeAbilitySystem ( ) ;
}
}
SetActorHiddenInGame ( true ) ;
}
void ALyraCharacter : : OnMovementModeChanged ( EMovementMode PrevMovementMode , uint8 PreviousCustomMode )
{
Super : : OnMovementModeChanged ( PrevMovementMode , PreviousCustomMode ) ;
ULyraCharacterMovementComponent * LyraMoveComp = CastChecked < ULyraCharacterMovementComponent > ( GetCharacterMovement ( ) ) ;
SetMovementModeTag ( PrevMovementMode , PreviousCustomMode , false ) ;
SetMovementModeTag ( LyraMoveComp - > MovementMode , LyraMoveComp - > CustomMovementMode , true ) ;
}
void ALyraCharacter : : SetMovementModeTag ( EMovementMode MovementMode , uint8 CustomMovementMode , bool bTagEnabled )
{
if ( ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
const FLyraGameplayTags & GameplayTags = FLyraGameplayTags : : Get ( ) ;
const FGameplayTag * MovementModeTag = nullptr ;
if ( MovementMode = = MOVE_Custom )
{
MovementModeTag = GameplayTags . CustomMovementModeTagMap . Find ( CustomMovementMode ) ;
}
else
{
MovementModeTag = GameplayTags . MovementModeTagMap . Find ( MovementMode ) ;
}
if ( MovementModeTag & & MovementModeTag - > IsValid ( ) )
{
LyraASC - > SetLooseGameplayTagCount ( * MovementModeTag , ( bTagEnabled ? 1 : 0 ) ) ;
}
}
}
void ALyraCharacter : : ToggleCrouch ( )
{
const ULyraCharacterMovementComponent * LyraMoveComp = CastChecked < ULyraCharacterMovementComponent > ( GetCharacterMovement ( ) ) ;
if ( bIsCrouched | | LyraMoveComp - > bWantsToCrouch )
{
UnCrouch ( ) ;
}
else if ( LyraMoveComp - > IsMovingOnGround ( ) )
{
Crouch ( ) ;
}
}
void ALyraCharacter : : OnStartCrouch ( float HalfHeightAdjust , float ScaledHalfHeightAdjust )
{
if ( ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
LyraASC - > SetLooseGameplayTagCount ( FLyraGameplayTags : : Get ( ) . Status_Crouching , 1 ) ;
}
Super : : OnStartCrouch ( HalfHeightAdjust , ScaledHalfHeightAdjust ) ;
}
void ALyraCharacter : : OnEndCrouch ( float HalfHeightAdjust , float ScaledHalfHeightAdjust )
{
if ( ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponent ( ) )
{
LyraASC - > SetLooseGameplayTagCount ( FLyraGameplayTags : : Get ( ) . Status_Crouching , 0 ) ;
}
Super : : OnEndCrouch ( HalfHeightAdjust , ScaledHalfHeightAdjust ) ;
}
bool ALyraCharacter : : CanJumpInternal_Implementation ( ) const
{
// same as ACharacter's implementation but without the crouch check
return JumpIsAllowedInternal ( ) ;
}
void ALyraCharacter : : OnRep_ReplicatedAcceleration ( )
{
if ( ULyraCharacterMovementComponent * LyraMovementComponent = Cast < ULyraCharacterMovementComponent > ( GetCharacterMovement ( ) ) )
{
// Decompress Acceleration
const double MaxAccel = LyraMovementComponent - > MaxAcceleration ;
const double AccelXYMagnitude = double ( ReplicatedAcceleration . AccelXYMagnitude ) * MaxAccel / 255.0 ; // [0, 255] -> [0, MaxAccel]
const double AccelXYRadians = double ( ReplicatedAcceleration . AccelXYRadians ) * TWO_PI / 255.0 ; // [0, 255] -> [0, 2PI]
FVector UnpackedAcceleration ( FVector : : ZeroVector ) ;
FMath : : PolarToCartesian ( AccelXYMagnitude , AccelXYRadians , UnpackedAcceleration . X , UnpackedAcceleration . Y ) ;
UnpackedAcceleration . Z = double ( ReplicatedAcceleration . AccelZ ) * MaxAccel / 127.0 ; // [-127, 127] -> [-MaxAccel, MaxAccel]
LyraMovementComponent - > SetReplicatedAcceleration ( UnpackedAcceleration ) ;
}
}
void ALyraCharacter : : SetGenericTeamId ( const FGenericTeamId & NewTeamID )
{
if ( GetController ( ) = = nullptr )
{
if ( HasAuthority ( ) )
{
const FGenericTeamId OldTeamID = MyTeamID ;
MyTeamID = NewTeamID ;
ConditionalBroadcastTeamChanged ( this , OldTeamID , MyTeamID ) ;
}
else
{
UE_LOG ( LogLyraTeams , Error , TEXT ( " You can't set the team ID on a character (%s) except on the authority " ) , * GetPathNameSafe ( this ) ) ;
}
}
else
{
UE_LOG ( LogLyraTeams , Error , TEXT ( " You can't set the team ID on a possessed character (%s); it's driven by the associated controller " ) , * GetPathNameSafe ( this ) ) ;
}
}
FGenericTeamId ALyraCharacter : : GetGenericTeamId ( ) const
{
return MyTeamID ;
}
FOnLyraTeamIndexChangedDelegate * ALyraCharacter : : GetOnTeamIndexChangedDelegate ( )
{
return & OnTeamChangedDelegate ;
}
void ALyraCharacter : : OnControllerChangedTeam ( UObject * TeamAgent , int32 OldTeam , int32 NewTeam )
{
const FGenericTeamId MyOldTeamID = MyTeamID ;
MyTeamID = IntegerToGenericTeamId ( NewTeam ) ;
ConditionalBroadcastTeamChanged ( this , MyOldTeamID , MyTeamID ) ;
}
void ALyraCharacter : : OnRep_MyTeamID ( FGenericTeamId OldTeamID )
{
ConditionalBroadcastTeamChanged ( this , OldTeamID , MyTeamID ) ;
}