RealtimeStyleTransferRuntime/Source/LyraGame/Character/LyraPawnExtensionComponent.cpp

258 lines
7.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LyraPawnExtensionComponent.h"
#include "LyraLogChannels.h"
#include "Net/UnrealNetwork.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/Controller.h"
#include "LyraPawnData.h"
#include "AbilitySystem/LyraAbilitySystemComponent.h"
ULyraPawnExtensionComponent::ULyraPawnExtensionComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryComponentTick.bStartWithTickEnabled = false;
PrimaryComponentTick.bCanEverTick = false;
SetIsReplicatedByDefault(true);
PawnData = nullptr;
AbilitySystemComponent = nullptr;
bPawnReadyToInitialize = false;
}
void ULyraPawnExtensionComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ULyraPawnExtensionComponent, PawnData);
}
void ULyraPawnExtensionComponent::OnRegister()
{
Super::OnRegister();
const APawn* Pawn = GetPawn<APawn>();
ensureAlwaysMsgf((Pawn != nullptr), TEXT("LyraPawnExtensionComponent on [%s] can only be added to Pawn actors."), *GetNameSafe(GetOwner()));
TArray<UActorComponent*> PawnExtensionComponents;
Pawn->GetComponents(ULyraPawnExtensionComponent::StaticClass(), PawnExtensionComponents);
ensureAlwaysMsgf((PawnExtensionComponents.Num() == 1), TEXT("Only one LyraPawnExtensionComponent should exist on [%s]."), *GetNameSafe(GetOwner()));
}
void ULyraPawnExtensionComponent::SetPawnData(const ULyraPawnData* InPawnData)
{
check(InPawnData);
bPawnReadyToInitialize = false;
APawn* Pawn = GetPawnChecked<APawn>();
if (Pawn->GetLocalRole() != ROLE_Authority)
{
return;
}
if (PawnData)
{
UE_LOG(LogLyra, Error, TEXT("Trying to set PawnData [%s] on pawn [%s] that already has valid PawnData [%s]."), *GetNameSafe(InPawnData), *GetNameSafe(Pawn), *GetNameSafe(PawnData));
return;
}
PawnData = InPawnData;
Pawn->ForceNetUpdate();
CheckPawnReadyToInitialize();
}
void ULyraPawnExtensionComponent::OnRep_PawnData()
{
CheckPawnReadyToInitialize();
}
void ULyraPawnExtensionComponent::InitializeAbilitySystem(ULyraAbilitySystemComponent* InASC, AActor* InOwnerActor)
{
check(InASC);
check(InOwnerActor);
if (AbilitySystemComponent == InASC)
{
// The ability system component hasn't changed.
return;
}
if (AbilitySystemComponent)
{
// Clean up the old ability system component.
UninitializeAbilitySystem();
}
APawn* Pawn = GetPawnChecked<APawn>();
AActor* ExistingAvatar = InASC->GetAvatarActor();
UE_LOG(LogLyra, Verbose, TEXT("Setting up ASC [%s] on pawn [%s] owner [%s], existing [%s] "), *GetNameSafe(InASC), *GetNameSafe(Pawn), *GetNameSafe(InOwnerActor), *GetNameSafe(ExistingAvatar));
if ((ExistingAvatar != nullptr) && (ExistingAvatar != Pawn))
{
UE_LOG(LogLyra, Log, TEXT("Existing avatar (authority=%d)"), ExistingAvatar->HasAuthority() ? 1 : 0);
// There is already a pawn acting as the ASC's avatar, so we need to kick it out
// This can happen on clients if they're lagged: their new pawn is spawned + possessed before the dead one is removed
ensure(!ExistingAvatar->HasAuthority());
if (ULyraPawnExtensionComponent* OtherExtensionComponent = FindPawnExtensionComponent(ExistingAvatar))
{
OtherExtensionComponent->UninitializeAbilitySystem();
}
}
AbilitySystemComponent = InASC;
AbilitySystemComponent->InitAbilityActorInfo(InOwnerActor, Pawn);
if (ensure(PawnData))
{
InASC->SetTagRelationshipMapping(PawnData->TagRelationshipMapping);
}
OnAbilitySystemInitialized.Broadcast();
}
void ULyraPawnExtensionComponent::UninitializeAbilitySystem()
{
if (!AbilitySystemComponent)
{
return;
}
// Uninitialize the ASC if we're still the avatar actor (otherwise another pawn already did it when they became the avatar actor)
if (AbilitySystemComponent->GetAvatarActor() == GetOwner())
{
AbilitySystemComponent->CancelAbilities(nullptr, nullptr);
AbilitySystemComponent->ClearAbilityInput();
AbilitySystemComponent->RemoveAllGameplayCues();
if (AbilitySystemComponent->GetOwnerActor() != nullptr)
{
AbilitySystemComponent->SetAvatarActor(nullptr);
}
else
{
// If the ASC doesn't have a valid owner, we need to clear *all* actor info, not just the avatar pairing
AbilitySystemComponent->ClearActorInfo();
}
OnAbilitySystemUninitialized.Broadcast();
}
AbilitySystemComponent = nullptr;
}
void ULyraPawnExtensionComponent::HandleControllerChanged()
{
if (AbilitySystemComponent && (AbilitySystemComponent->GetAvatarActor() == GetPawnChecked<APawn>()))
{
ensure(AbilitySystemComponent->AbilityActorInfo->OwnerActor == AbilitySystemComponent->GetOwnerActor());
if (AbilitySystemComponent->GetOwnerActor() == nullptr)
{
UninitializeAbilitySystem();
}
else
{
AbilitySystemComponent->RefreshAbilityActorInfo();
}
}
CheckPawnReadyToInitialize();
}
void ULyraPawnExtensionComponent::HandlePlayerStateReplicated()
{
CheckPawnReadyToInitialize();
}
void ULyraPawnExtensionComponent::SetupPlayerInputComponent()
{
CheckPawnReadyToInitialize();
}
bool ULyraPawnExtensionComponent::CheckPawnReadyToInitialize()
{
if (bPawnReadyToInitialize)
{
return true;
}
// Pawn data is required.
if (!PawnData)
{
return false;
}
APawn* Pawn = GetPawnChecked<APawn>();
const bool bHasAuthority = Pawn->HasAuthority();
const bool bIsLocallyControlled = Pawn->IsLocallyControlled();
if (bHasAuthority || bIsLocallyControlled)
{
// Check for being possessed by a controller.
if (!GetController<AController>())
{
return false;
}
}
// Allow pawn components to have requirements.
TArray<UActorComponent*> InteractableComponents = Pawn->GetComponentsByInterface(ULyraReadyInterface::StaticClass());
for (UActorComponent* InteractableComponent : InteractableComponents)
{
const ILyraReadyInterface* Ready = CastChecked<ILyraReadyInterface>(InteractableComponent);
if (!Ready->IsPawnComponentReadyToInitialize())
{
return false;
}
}
// Pawn is ready to initialize.
bPawnReadyToInitialize = true;
OnPawnReadyToInitialize.Broadcast();
BP_OnPawnReadyToInitialize.Broadcast();
return true;
}
void ULyraPawnExtensionComponent::OnPawnReadyToInitialize_RegisterAndCall(FSimpleMulticastDelegate::FDelegate Delegate)
{
if (!OnPawnReadyToInitialize.IsBoundToObject(Delegate.GetUObject()))
{
OnPawnReadyToInitialize.Add(Delegate);
}
if (bPawnReadyToInitialize)
{
Delegate.Execute();
}
}
void ULyraPawnExtensionComponent::OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate Delegate)
{
if (!OnAbilitySystemInitialized.IsBoundToObject(Delegate.GetUObject()))
{
OnAbilitySystemInitialized.Add(Delegate);
}
if (AbilitySystemComponent)
{
Delegate.Execute();
}
}
void ULyraPawnExtensionComponent::OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate Delegate)
{
if (!OnAbilitySystemUninitialized.IsBoundToObject(Delegate.GetUObject()))
{
OnAbilitySystemUninitialized.Add(Delegate);
}
}