272 lines
7.7 KiB
C++
272 lines
7.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LyraPlayerState.h"
|
|
#include "LyraLogChannels.h"
|
|
#include "Net/UnrealNetwork.h"
|
|
#include "LyraPlayerController.h"
|
|
#include "Character/LyraPawnExtensionComponent.h"
|
|
#include "AbilitySystem/LyraAbilitySystemComponent.h"
|
|
#include "AbilitySystem/LyraAbilitySet.h"
|
|
#include "AbilitySystem/Attributes/LyraHealthSet.h"
|
|
#include "AbilitySystem/Attributes/LyraCombatSet.h"
|
|
#include "Character/LyraPawnData.h"
|
|
#include "Components/GameFrameworkComponentManager.h"
|
|
#include "GameFramework/GameplayMessageSubsystem.h"
|
|
|
|
//@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"
|
|
#include "GameModes/LyraExperienceManagerComponent.h"
|
|
|
|
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()))
|
|
{
|
|
PawnExtComp->CheckPawnReadyToInitialize();
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|