// Copyright Epic Games, Inc. All Rights Reserved. #include "GameFeatureAction_AddWidget.h" #include "Components/GameFrameworkComponentManager.h" #include "GameFeaturesSubsystemSettings.h" #include "Engine/AssetManager.h" #include "CommonUIExtensions.h" #include "Engine/Engine.h" #define LOCTEXT_NAMESPACE "LyraGameFeatures" ////////////////////////////////////////////////////////////////////// // UGameFeatureAction_AddWidgets void UGameFeatureAction_AddWidgets::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context) { Super::OnGameFeatureDeactivating(Context); FPerContextData* ActiveData = ContextData.Find(Context); if ensure(ActiveData) { Reset(*ActiveData); } } #if WITH_EDITORONLY_DATA void UGameFeatureAction_AddWidgets::AddAdditionalAssetBundleData(FAssetBundleData& AssetBundleData) { for (const FLyraHUDElementEntry& Entry : Widgets) { AssetBundleData.AddBundleAsset(UGameFeaturesSubsystemSettings::LoadStateClient, Entry.WidgetClass.ToSoftObjectPath()); } } #endif #if WITH_EDITOR EDataValidationResult UGameFeatureAction_AddWidgets::IsDataValid(TArray& ValidationErrors) { EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(ValidationErrors), EDataValidationResult::Valid); { int32 EntryIndex = 0; for (const FLyraHUDLayoutRequest& Entry : Layout) { if (Entry.LayoutClass.IsNull()) { Result = EDataValidationResult::Invalid; ValidationErrors.Add(FText::Format(LOCTEXT("LayoutHasNullClass", "Null WidgetClass at index {0} in Layout"), FText::AsNumber(EntryIndex))); } if (!Entry.LayerID.IsValid()) { Result = EDataValidationResult::Invalid; ValidationErrors.Add(FText::Format(LOCTEXT("LayoutHasNoTag", "LayerID is not set at index {0} in Widgets"), FText::AsNumber(EntryIndex))); } ++EntryIndex; } } { int32 EntryIndex = 0; for (const FLyraHUDElementEntry& Entry : Widgets) { if (Entry.WidgetClass.IsNull()) { Result = EDataValidationResult::Invalid; ValidationErrors.Add(FText::Format(LOCTEXT("EntryHasNullClass", "Null WidgetClass at index {0} in Widgets"), FText::AsNumber(EntryIndex))); } if (!Entry.SlotID.IsValid()) { Result = EDataValidationResult::Invalid; ValidationErrors.Add(FText::Format(LOCTEXT("EntryHasNoTag", "SlotID is not set at index {0} in Widgets"), FText::AsNumber(EntryIndex))); } ++EntryIndex; } } return Result; } #endif void UGameFeatureAction_AddWidgets::AddToWorld(const FWorldContext& WorldContext, const FGameFeatureStateChangeContext& ChangeContext) { UWorld* World = WorldContext.World(); UGameInstance* GameInstance = WorldContext.OwningGameInstance; FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); if ((GameInstance != nullptr) && (World != nullptr) && World->IsGameWorld()) { if (UGameFrameworkComponentManager* ComponentManager = UGameInstance::GetSubsystem(GameInstance)) { TSoftClassPtr HUDActorClass = ALyraHUD::StaticClass(); TSharedPtr ExtensionRequestHandle = ComponentManager->AddExtensionHandler( HUDActorClass, UGameFrameworkComponentManager::FExtensionHandlerDelegate::CreateUObject(this, &ThisClass::HandleActorExtension, ChangeContext)); ActiveData.ComponentRequests.Add(ExtensionRequestHandle); } } } void UGameFeatureAction_AddWidgets::Reset(FPerContextData& ActiveData) { ActiveData.ComponentRequests.Empty(); ActiveData.LayoutsAdded.Empty(); for (FUIExtensionHandle& Handle : ActiveData.ExtensionHandles) { Handle.Unregister(); } ActiveData.ExtensionHandles.Reset(); } void UGameFeatureAction_AddWidgets::HandleActorExtension(AActor* Actor, FName EventName, FGameFeatureStateChangeContext ChangeContext) { FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionRemoved) || (EventName == UGameFrameworkComponentManager::NAME_ReceiverRemoved)) { RemoveWidgets(Actor, ActiveData); } else if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (EventName == UGameFrameworkComponentManager::NAME_GameActorReady)) { AddWidgets(Actor, ActiveData); } } void UGameFeatureAction_AddWidgets::AddWidgets(AActor* Actor, FPerContextData& ActiveData) { ALyraHUD* HUD = CastChecked(Actor); if (ULocalPlayer* LocalPlayer = Cast(HUD->GetOwningPlayerController()->Player)) { for (const FLyraHUDLayoutRequest& Entry : Layout) { if (TSubclassOf ConcreteWidgetClass = Entry.LayoutClass.Get()) { ActiveData.LayoutsAdded.Add(UCommonUIExtensions::PushContentToLayer_ForPlayer(LocalPlayer, Entry.LayerID, ConcreteWidgetClass)); } } UUIExtensionSubsystem* ExtensionSubsystem = HUD->GetWorld()->GetSubsystem(); for (const FLyraHUDElementEntry& Entry : Widgets) { ActiveData.ExtensionHandles.Add(ExtensionSubsystem->RegisterExtensionAsWidgetForContext(Entry.SlotID, LocalPlayer, Entry.WidgetClass.Get(), -1)); } } } void UGameFeatureAction_AddWidgets::RemoveWidgets(AActor* Actor, FPerContextData& ActiveData) { ALyraHUD* HUD = CastChecked(Actor); for (TWeakObjectPtr& AddedLayout : ActiveData.LayoutsAdded) { if (AddedLayout.IsValid()) { AddedLayout->DeactivateWidget(); } } ActiveData.LayoutsAdded.Reset(); for (FUIExtensionHandle& Handle : ActiveData.ExtensionHandles) { Handle.Unregister(); } ActiveData.ExtensionHandles.Reset(); } #undef LOCTEXT_NAMESPACE