// Copyright Epic Games, Inc. All Rights Reserved. #include "Actions/AsyncAction_CreateWidgetAsync.h" #include "Blueprint/WidgetBlueprintLibrary.h" #include "CommonUIExtensions.h" #include "Engine/AssetManager.h" #include "Engine/Engine.h" #include "Engine/GameInstance.h" #include "Engine/StreamableManager.h" #include "Engine/World.h" #include "GameFramework/PlayerController.h" #include "HAL/Platform.h" #include "Logging/LogVerbosity.h" #include "Templates/SubclassOf.h" #include "UObject/Stack.h" #include "UObject/UnrealNames.h" #include "UObject/WeakObjectPtr.h" class UUserWidget; static const FName InputFilterReason_Template = FName(TEXT("CreatingWidgetAsync")); UAsyncAction_CreateWidgetAsync::UAsyncAction_CreateWidgetAsync(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bSuspendInputUntilComplete(true) { } UAsyncAction_CreateWidgetAsync* UAsyncAction_CreateWidgetAsync::CreateWidgetAsync(UObject* InWorldContextObject, TSoftClassPtr InUserWidgetSoftClass, APlayerController* InOwningPlayer, bool bSuspendInputUntilComplete) { if (InUserWidgetSoftClass.IsNull()) { FFrame::KismetExecutionMessage(TEXT("CreateWidgetAsync was passed a null UserWidgetSoftClass"), ELogVerbosity::Error); return nullptr; } UWorld* World = GEngine->GetWorldFromContextObject(InWorldContextObject, EGetWorldErrorMode::LogAndReturnNull); UAsyncAction_CreateWidgetAsync* Action = NewObject(); Action->UserWidgetSoftClass = InUserWidgetSoftClass; Action->OwningPlayer = InOwningPlayer; Action->World = World; Action->GameInstance = World->GetGameInstance(); Action->bSuspendInputUntilComplete = bSuspendInputUntilComplete; Action->RegisterWithGameInstance(World); return Action; } void UAsyncAction_CreateWidgetAsync::Activate() { SuspendInputToken = bSuspendInputUntilComplete ? UCommonUIExtensions::SuspendInputForPlayer(OwningPlayer.Get(), InputFilterReason_Template) : NAME_None; TWeakObjectPtr LocalWeakThis(this); StreamingHandle = UAssetManager::Get().GetStreamableManager().RequestAsyncLoad( UserWidgetSoftClass.ToSoftObjectPath(), FStreamableDelegate::CreateUObject(this, &ThisClass::OnWidgetLoaded), FStreamableManager::AsyncLoadHighPriority ); // Setup a cancel delegate so that we can resume input if this handler is canceled. StreamingHandle->BindCancelDelegate(FStreamableDelegate::CreateWeakLambda(this, [this]() { UCommonUIExtensions::ResumeInputForPlayer(OwningPlayer.Get(), SuspendInputToken); }) ); } void UAsyncAction_CreateWidgetAsync::Cancel() { Super::Cancel(); if (StreamingHandle.IsValid()) { StreamingHandle->CancelHandle(); StreamingHandle.Reset(); } } void UAsyncAction_CreateWidgetAsync::OnWidgetLoaded() { if (bSuspendInputUntilComplete) { UCommonUIExtensions::ResumeInputForPlayer(OwningPlayer.Get(), SuspendInputToken); } // If the load as successful, create it, otherwise don't complete this. TSubclassOf UserWidgetClass = UserWidgetSoftClass.Get(); if (UserWidgetClass) { UUserWidget* UserWidget = UWidgetBlueprintLibrary::Create(World.Get(), UserWidgetClass, OwningPlayer.Get()); OnComplete.Broadcast(UserWidget); } StreamingHandle.Reset(); SetReadyToDestroy(); }