Download

Cook an unreferenced Widget Blueprint

Hi all,

So I’ve got a custom C++ controller class in which I instantiate a UMG blueprint for my main menu using this:



	if (!mainMenuWidgetClass)
	{
		// Not populated, let's try grab our default one.
		// This is the expected code path.
		static ConstructorHelpers::FObjectFinder<UBlueprint> mainMenuBP(TEXT("WidgetBlueprint'/Game/UI/MainMenu/MainMenuWidget.MainMenuWidget'"));
		if (mainMenuBP.Succeeded())
		{
			mainMenuWidgetClass = (UClass *)mainMenuBP.Object->GeneratedClass;
		}
	}


This all works fine using PIE or Standalone, but when I try package it the launched version complains it can’t find it.

I’ve tried adding the directory containing it to the additional directories to cook. I’ve also tried telling it to cook everything under content, neither of which fix it.
Then I tried adding a variable to the level blueprint that got set to that class OnBegin, but that didn’t fix it either.

I’m expecting a proposed work around will be to create a Blueprint player controller class and inherit from my C++ one and use it to set the type. But the problem is to do that and set the value I either then need to reference that Blueprint player controller class in my C++ GameMode, which puts me back to the same issue, or I need to make a Blueprint GameMode, which I can’t do because I have other C++ GameModes which inherit from my base one and doing so would mean they would need to inherit from a Blueprint class.

Cheers,

Alan.

UWidgetBlueprints do not cook. Nothing in an editor module can be referenced in a shipping title. You must reference the generated class, not the blueprint.

Hi Nick,

I’m trying to reference the generated class without using the widget blueprint string etc as above, but I can’t find anywhere that details how this is supposed to be done.

I’ve found the obj that UE creates from the blueprint and dumpbinned it’s headers to confirm that the classname is just the blueprint classname with a U prefixed, UMainMenuWidget in my case. But it doesn’t appear that the compilation process generates headers that I can include to reference this type.

I’ve also tried replacing the class finding section with:



		UObject * ClassPackage = ANY_PACKAGE;
		mainMenuWidgetClass = FindObject<UClass>(ClassPackage, TEXT("/Game/UI/MainMenu/MainMenuWidget.MainMenuWidget_C"));


Which works in editor, but not when packaged. Then also tried:



		static ConstructorHelpers::FObjectFinder<UClass> mainMenuBP(TEXT("/Game/UI/MainMenu/MainMenuWidget.MainMenuWidget_C"));
		if (mainMenuBP.Succeeded())
		{
			UE_LOG(LogTemp, Warning, TEXT("Found class"));
			mainMenuWidgetClass = mainMenuBP.Object->StaticClass();
		}


Which says it found the class, but then nothing appears (Perhaps StaticClass is non-virtual, so I’m getting the UClass implementation of it, but that’s just a random guess). I’ve also tried switching the UClass there with UUserWidget, but that then doesn’t find it at all, which makes me suss on the type of whatever it’s throwing back, but that’s also just my making assumptions.

Everywhere that I’ve used those content type paths to the class, I’ve also tried using the classname from the compiled object, but that doesn’t even work in editor. Searching has turned up a bunch of people asking the same question (how to instance a Blueprint from in C++), but I’ve not managed to find any answer that work.

If you could provide details of how I should reference that generated class from C++ I’d be grateful beyond emoticons.

Cheers,

Alan.

Woot! Success.

This is what works:



		static ConstructorHelpers::FClassFinder<UUserWidget> mainMenuWidgetClassFinder(TEXT("/Game/UI/MainMenu/MainMenuWidget.MainMenuWidget_C"));
		if (mainMenuWidgetClassFinder.Succeeded())
		{
			mainMenuWidgetClass = mainMenuWidgetClassFinder.Class;
		}


Now to mark this thread as resolved.

Cheers,

Alan

EDIT: Actually, I should make this complete for someone else looking to do this.

First part is half optional - I made a variable to store the type of widget wanted. Making it a property exposes it to the UI. I’m doing this in my PlayerController, but same principles apply if you do it elsewhere.



	// Reference UMG Main Menu Asset Class in the Editor
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Widgets")
	TSubclassOf<class UUserWidget> mainMenuWidgetClass;


I also have a UUserWidget * mainMenuWidget so that I can keep around the reference to the instance, but that’s irrelevant other than knowing what the variable is in the following PlayerController constructor code.

To get the path to your UMG asset, right click on it in the editor and choose copy reference. Then take the parts between the single quotes and append “_C”. (no quotes)



MyPlayerController::MyPlayerController(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	// If it hasn't been set through the UI, then let's find one we know about
	if (!mainMenuWidgetClass)
	{
		// Not populated, let's try grab our default one.
		// This is the expected code path.
		static ConstructorHelpers::FClassFinder<UUserWidget> mainMenuWidgetClassFinder(TEXT("/Game/UI/MainMenu/MainMenuWidget.MainMenuWidget_C"));
		if (mainMenuWidgetClassFinder.Succeeded())
		{
			// Found the class using the reference path to the UMG asset
			mainMenuWidgetClass = mainMenuWidgetClassFinder.Class;
		}

	}
}


Instantiating your widget is straightforward from here. I do it in BeginPlay(), but that’s because this is my main menu.



		// Check we have a class to instantiate
		if (mainMenuWidgetClass)
		{
			// Create the main menu widget
			mainMenuWidget = CreateWidget<UUserWidget>(this, mainMenuWidgetClass);

			if (mainMenuWidget)
			{
				// Create one of these, or store it in your class, if you want to let your UI receive interaction events, which you totally do if you bothered making a menu
				FInputModeGameAndUI inputModeSettings;

				inputModeSettings.SetWidgetToFocus(mainMenuWidget->GetCachedWidget());
				SetInputMode(inputModeSettings);
				mainMenuWidget->AddToViewport();
			}
		}


And that’s it for getting your UMG from in C++, kicking it into the viewport, and letting it receive input.

Oh, editing the title on the first post didn’t rename the thread, so I have no idea how to do it. Hopefully it’s for a reason less embarassing than I’m an imbicile, and it’s something only moderators can do. If someone could make this thread look like the bastion of satisfaction that it is (or tell me how to), this thread would be an even greater example of the true power of friendship, or something.