RealtimeStyleTransferRuntime/Source/LyraGame/GameModes/AsyncAction_ExperienceReady...

94 lines
2.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AsyncAction_ExperienceReady.h"
#include "Engine/AssetManager.h"
#include "Engine/StreamableManager.h"
#include "Engine/Engine.h"
#include "Engine/GameInstance.h"
#include "TimerManager.h"
#include "GameModes/LyraExperienceManagerComponent.h"
UAsyncAction_ExperienceReady::UAsyncAction_ExperienceReady(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
UAsyncAction_ExperienceReady* UAsyncAction_ExperienceReady::WaitForExperienceReady(UObject* InWorldContextObject)
{
UAsyncAction_ExperienceReady* Action = nullptr;
if (UWorld* World = GEngine->GetWorldFromContextObject(InWorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
Action = NewObject<UAsyncAction_ExperienceReady>();
Action->WorldPtr = World;
Action->RegisterWithGameInstance(World);
}
return Action;
}
void UAsyncAction_ExperienceReady::Activate()
{
if (UWorld* World = WorldPtr.Get())
{
if (AGameStateBase* GameState = World->GetGameState())
{
Step2_ListenToExperienceLoading(GameState);
}
else
{
World->GameStateSetEvent.AddUObject(this, &ThisClass::Step1_HandleGameStateSet);
}
}
else
{
// No world so we'll never finish naturally
SetReadyToDestroy();
}
}
void UAsyncAction_ExperienceReady::Step1_HandleGameStateSet(AGameStateBase* GameState)
{
if (UWorld* World = WorldPtr.Get())
{
World->GameStateSetEvent.RemoveAll(this);
}
Step2_ListenToExperienceLoading(GameState);
}
void UAsyncAction_ExperienceReady::Step2_ListenToExperienceLoading(AGameStateBase* GameState)
{
check(GameState);
ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>();
check(ExperienceComponent);
if (ExperienceComponent->IsExperienceLoaded())
{
UWorld* World = GameState->GetWorld();
check(World);
// The experience happened to be already loaded, but still delay a frame to
// make sure people don't write stuff that relies on this always being true
//@TODO: Consider not delaying for dynamically spawned stuff / any time after the loading screen has dropped?
//@TODO: Maybe just inject a random 0-1s delay in the experience load itself?
World->GetTimerManager().SetTimerForNextTick(FTimerDelegate::CreateUObject(this, &ThisClass::Step4_BroadcastReady));
}
else
{
ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::Step3_HandleExperienceLoaded));
}
}
void UAsyncAction_ExperienceReady::Step3_HandleExperienceLoaded(const ULyraExperienceDefinition* CurrentExperience)
{
Step4_BroadcastReady();
}
void UAsyncAction_ExperienceReady::Step4_BroadcastReady()
{
OnReady.Broadcast();
SetReadyToDestroy();
}