RealtimeStyleTransferRuntime/Source/LyraGame/Player/LyraPlayerState.cpp

272 lines
7.7 KiB
C++
Raw Normal View History

2022-05-23 18:41:30 +00:00
// 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);
}
}