2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LyraPlayerState.h"
2022-09-13 07:18:28 +00:00
2022-05-23 18:41:30 +00:00
# include "AbilitySystem/Attributes/LyraCombatSet.h"
2022-09-13 07:18:28 +00:00
# include "AbilitySystem/Attributes/LyraHealthSet.h"
# include "AbilitySystem/LyraAbilitySet.h"
# include "AbilitySystem/LyraAbilitySystemComponent.h"
# include "AbilitySystemComponent.h"
2022-05-23 18:41:30 +00:00
# include "Character/LyraPawnData.h"
2022-09-13 07:18:28 +00:00
# include "Character/LyraPawnExtensionComponent.h"
2022-05-23 18:41:30 +00:00
# include "Components/GameFrameworkComponentManager.h"
2022-09-13 07:18:28 +00:00
# include "Containers/Array.h"
# include "Containers/UnrealString.h"
# include "CoreTypes.h"
# include "Delegates/Delegate.h"
# include "Engine/EngineBaseTypes.h"
# include "Engine/EngineTypes.h"
# include "Engine/World.h"
# include "GameFramework/GameStateBase.h"
2022-05-23 18:41:30 +00:00
# include "GameFramework/GameplayMessageSubsystem.h"
2022-09-13 07:18:28 +00:00
# include "GameFramework/Pawn.h"
# include "GameModes/LyraExperienceManagerComponent.h"
2022-05-23 18:41:30 +00:00
//@TODO: Would like to isolate this a bit better to get the pawn data in here without this having to know about other stuff
# include "GameModes/LyraGameMode.h"
2022-09-13 07:18:28 +00:00
# include "GameplayTagContainer.h"
# include "Logging/LogCategory.h"
# include "Logging/LogMacros.h"
# include "LyraLogChannels.h"
# include "LyraPlayerController.h"
# include "Misc/AssertionMacros.h"
# include "Net/Core/PushModel/PushModel.h"
# include "Net/UnrealNetwork.h"
# include "Trace/Detail/Channel.h"
# include "UObject/NameTypes.h"
# include "UObject/UObjectBaseUtility.h"
class AController ;
class APlayerState ;
class FLifetimeProperty ;
2022-05-23 18:41:30 +00:00
const FName ALyraPlayerState : : NAME_LyraAbilityReady ( " LyraAbilitiesReady " ) ;
ALyraPlayerState : : ALyraPlayerState ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
, MyPlayerConnectionType ( ELyraPlayerConnectionType : : Player )
{
AbilitySystemComponent = ObjectInitializer . CreateDefaultSubobject < ULyraAbilitySystemComponent > ( this , TEXT ( " AbilitySystemComponent " ) ) ;
AbilitySystemComponent - > SetIsReplicated ( true ) ;
AbilitySystemComponent - > SetReplicationMode ( EGameplayEffectReplicationMode : : Mixed ) ;
CreateDefaultSubobject < ULyraHealthSet > ( TEXT ( " HealthSet " ) ) ;
CreateDefaultSubobject < ULyraCombatSet > ( TEXT ( " CombatSet " ) ) ;
// AbilitySystemComponent needs to be updated at a high frequency.
NetUpdateFrequency = 100.0f ;
MyTeamID = FGenericTeamId : : NoTeam ;
MySquadID = INDEX_NONE ;
}
void ALyraPlayerState : : PreInitializeComponents ( )
{
Super : : PreInitializeComponents ( ) ;
}
void ALyraPlayerState : : Reset ( )
{
Super : : Reset ( ) ;
}
void ALyraPlayerState : : ClientInitialize ( AController * C )
{
Super : : ClientInitialize ( C ) ;
if ( ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( GetPawn ( ) ) )
{
2022-09-13 07:18:28 +00:00
PawnExtComp - > CheckDefaultInitialization ( ) ;
2022-05-23 18:41:30 +00:00
}
}
void ALyraPlayerState : : CopyProperties ( APlayerState * PlayerState )
{
Super : : CopyProperties ( PlayerState ) ;
//@TODO: Copy stats
}
void ALyraPlayerState : : OnDeactivated ( )
{
bool bDestroyDeactivatedPlayerState = false ;
switch ( GetPlayerConnectionType ( ) )
{
case ELyraPlayerConnectionType : : Player :
case ELyraPlayerConnectionType : : InactivePlayer :
//@TODO: Ask the experience if we should destroy disconnecting players immediately or leave them around
// (e.g., for long running servers where they might build up if lots of players cycle through)
bDestroyDeactivatedPlayerState = true ;
break ;
default :
bDestroyDeactivatedPlayerState = true ;
break ;
}
SetPlayerConnectionType ( ELyraPlayerConnectionType : : InactivePlayer ) ;
if ( bDestroyDeactivatedPlayerState )
{
Destroy ( ) ;
}
}
void ALyraPlayerState : : OnReactivated ( )
{
if ( GetPlayerConnectionType ( ) = = ELyraPlayerConnectionType : : InactivePlayer )
{
SetPlayerConnectionType ( ELyraPlayerConnectionType : : Player ) ;
}
}
void ALyraPlayerState : : OnExperienceLoaded ( const ULyraExperienceDefinition * /*CurrentExperience*/ )
{
if ( ALyraGameMode * LyraGameMode = GetWorld ( ) - > GetAuthGameMode < ALyraGameMode > ( ) )
{
if ( const ULyraPawnData * NewPawnData = LyraGameMode - > GetPawnDataForController ( GetOwningController ( ) ) )
{
SetPawnData ( NewPawnData ) ;
}
else
{
UE_LOG ( LogLyra , Error , TEXT ( " ALyraPlayerState::OnExperienceLoaded(): Unable to find PawnData to initialize player state [%s]! " ) , * GetNameSafe ( this ) ) ;
}
}
}
void ALyraPlayerState : : GetLifetimeReplicatedProps ( TArray < FLifetimeProperty > & OutLifetimeProps ) const
{
Super : : GetLifetimeReplicatedProps ( OutLifetimeProps ) ;
FDoRepLifetimeParams SharedParams ;
SharedParams . bIsPushBased = true ;
DOREPLIFETIME_WITH_PARAMS_FAST ( ThisClass , PawnData , SharedParams ) ;
DOREPLIFETIME_WITH_PARAMS_FAST ( ThisClass , MyPlayerConnectionType , SharedParams )
DOREPLIFETIME_WITH_PARAMS_FAST ( ThisClass , MyTeamID , SharedParams ) ;
DOREPLIFETIME_WITH_PARAMS_FAST ( ThisClass , MySquadID , SharedParams ) ;
DOREPLIFETIME ( ThisClass , StatTags ) ;
}
ALyraPlayerController * ALyraPlayerState : : GetLyraPlayerController ( ) const
{
return Cast < ALyraPlayerController > ( GetOwner ( ) ) ;
}
UAbilitySystemComponent * ALyraPlayerState : : GetAbilitySystemComponent ( ) const
{
return GetLyraAbilitySystemComponent ( ) ;
}
void ALyraPlayerState : : PostInitializeComponents ( )
{
Super : : PostInitializeComponents ( ) ;
check ( AbilitySystemComponent ) ;
AbilitySystemComponent - > InitAbilityActorInfo ( this , GetPawn ( ) ) ;
if ( GetNetMode ( ) ! = NM_Client )
{
AGameStateBase * GameState = GetWorld ( ) - > GetGameState ( ) ;
check ( GameState ) ;
ULyraExperienceManagerComponent * ExperienceComponent = GameState - > FindComponentByClass < ULyraExperienceManagerComponent > ( ) ;
check ( ExperienceComponent ) ;
ExperienceComponent - > CallOrRegister_OnExperienceLoaded ( FOnLyraExperienceLoaded : : FDelegate : : CreateUObject ( this , & ThisClass : : OnExperienceLoaded ) ) ;
}
}
void ALyraPlayerState : : SetPawnData ( const ULyraPawnData * InPawnData )
{
check ( InPawnData ) ;
if ( GetLocalRole ( ) ! = ROLE_Authority )
{
return ;
}
if ( PawnData )
{
UE_LOG ( LogLyra , Error , TEXT ( " Trying to set PawnData [%s] on player state [%s] that already has valid PawnData [%s]. " ) , * GetNameSafe ( InPawnData ) , * GetNameSafe ( this ) , * GetNameSafe ( PawnData ) ) ;
return ;
}
MARK_PROPERTY_DIRTY_FROM_NAME ( ThisClass , PawnData , this ) ;
PawnData = InPawnData ;
for ( const ULyraAbilitySet * AbilitySet : PawnData - > AbilitySets )
{
if ( AbilitySet )
{
AbilitySet - > GiveToAbilitySystem ( AbilitySystemComponent , nullptr ) ;
}
}
UGameFrameworkComponentManager : : SendGameFrameworkComponentExtensionEvent ( this , NAME_LyraAbilityReady ) ;
ForceNetUpdate ( ) ;
}
void ALyraPlayerState : : OnRep_PawnData ( )
{
}
void ALyraPlayerState : : SetPlayerConnectionType ( ELyraPlayerConnectionType NewType )
{
MARK_PROPERTY_DIRTY_FROM_NAME ( ThisClass , MyPlayerConnectionType , this ) ;
MyPlayerConnectionType = NewType ;
}
void ALyraPlayerState : : SetSquadID ( int32 NewSquadId )
{
if ( HasAuthority ( ) )
{
MARK_PROPERTY_DIRTY_FROM_NAME ( ThisClass , MySquadID , this ) ;
MySquadID = NewSquadId ;
}
}
void ALyraPlayerState : : SetGenericTeamId ( const FGenericTeamId & NewTeamID )
{
if ( HasAuthority ( ) )
{
const FGenericTeamId OldTeamID = MyTeamID ;
MARK_PROPERTY_DIRTY_FROM_NAME ( ThisClass , MyTeamID , this ) ;
MyTeamID = NewTeamID ;
ConditionalBroadcastTeamChanged ( this , OldTeamID , NewTeamID ) ;
}
else
{
UE_LOG ( LogLyraTeams , Error , TEXT ( " Cannot set team for %s on non-authority " ) , * GetPathName ( this ) ) ;
}
}
FGenericTeamId ALyraPlayerState : : GetGenericTeamId ( ) const
{
return MyTeamID ;
}
FOnLyraTeamIndexChangedDelegate * ALyraPlayerState : : GetOnTeamIndexChangedDelegate ( )
{
return & OnTeamChangedDelegate ;
}
void ALyraPlayerState : : OnRep_MyTeamID ( FGenericTeamId OldTeamID )
{
ConditionalBroadcastTeamChanged ( this , OldTeamID , MyTeamID ) ;
}
void ALyraPlayerState : : OnRep_MySquadID ( )
{
//@TODO: Let the squad subsystem know (once that exists)
}
void ALyraPlayerState : : AddStatTagStack ( FGameplayTag Tag , int32 StackCount )
{
StatTags . AddStack ( Tag , StackCount ) ;
}
void ALyraPlayerState : : RemoveStatTagStack ( FGameplayTag Tag , int32 StackCount )
{
StatTags . RemoveStack ( Tag , StackCount ) ;
}
int32 ALyraPlayerState : : GetStatTagStackCount ( FGameplayTag Tag ) const
{
return StatTags . GetStackCount ( Tag ) ;
}
bool ALyraPlayerState : : HasStatTag ( FGameplayTag Tag ) const
{
return StatTags . ContainsTag ( Tag ) ;
}
void ALyraPlayerState : : ClientBroadcastMessage_Implementation ( const FLyraVerbMessage Message )
{
// This check is needed to prevent running the action when in standalone mode
if ( GetNetMode ( ) = = NM_Client )
{
UGameplayMessageSubsystem : : Get ( this ) . BroadcastMessage ( Message . Verb , Message ) ;
}
}