MenuInterface on InGameMenu is null when Quit is pressed

At 14:50 in video titled “43. Challenge: Leaving A Server”, Sam says “Remember the menu interface is set by a superclass. It’s a variable on a superclass.” However, every time I click Quit on the InGameMenu, this code below runs…

void UInGameMenu::QuitPressed()
{
	UE_LOG(LogTemp, Warning, TEXT("QuitPressed() called."));
	if (MenuInterface != nullptr)
	{
		UE_LOG(LogTemp, Warning, TEXT("MenuInterface is not null."));
		Teardown();
		MenuInterface->LoadMainMenuMap();
	} else
	{
		UE_LOG(LogTemp, Error, TEXT("MenuInterface is null."));
	}
}

and this is printed to the Output Log:

Warning: QuitPressed() called.
Error: MenuInterface is null.

I’ve checked the Github repo and I see that UPuzzlePlatformsGameInstance::InGameLoadMenu() calls SetMenuInterface(this) on the in-game menu, so I don’t understand why it would be null at the time Quit is clicked.

For comparison, my version of InGameLoadMenu() is below.

void UPuzzlePlatformsGameInstance::LoadInGameMenu()
{
	if (!InGameMenuClass) { return; }

	// Menu name changed to avoid shadowing
	UMenuWidget* InGameMenu = CreateWidget<UMenuWidget>(this, InGameMenuClass);
	if (!InGameMenu) { return; }

	InGameMenu->Setup();
	InGameMenu->SetMenuInterface(this);
}

I’d need to see the whole class to follow your code.

Can you share it? Thanks

No problem. Let me know if you need to see anything else.

PuzzlePlatformsGameInstance.h

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "Interfaces/OnlineSessionInterface.h"
#include "Menu/MenuInterface.h"
#include "PuzzlePlatformsGameInstance.generated.h"

UCLASS()
class PUZZLEPLATFORMS_API UPuzzlePlatformsGameInstance : public UGameInstance, public IMenuInterface
{
	GENERATED_BODY()

public:
	UPuzzlePlatformsGameInstance();

	virtual void Init() override;

	UFUNCTION(Exec, BlueprintCallable)
	void LoadMainMenu();

	UFUNCTION(Exec, BlueprintCallable)
	void LoadInGameMenu();

	UFUNCTION(Exec)
	virtual void Host() override;

	UFUNCTION(Exec)
	virtual void Join(const FString& Address) override;

	virtual void LoadMainMenuMap() override;

private:
	TSubclassOf<class UUserWidget> MainMenuClass;
	TSubclassOf<class UUserWidget> InGameMenuClass;

	UPROPERTY()
	class UMainMenu* MainMenu;

	IOnlineSessionPtr SessionInterface;

	void OnCreateSessionComplete(FName SessionName, bool bSuccess);
};

PuzzlePlatformsGameInstance.cpp

#include "PuzzlePlatformsGameInstance.h"
#include "Blueprint/UserWidget.h"
#include "Menu/MainMenu.h"
#include "Menu/MenuWidget.h"
#include "Menu/InGameMenu.h"
#include "OnlineSessionSettings.h"
#include "OnlineSubsystem.h"

UPuzzlePlatformsGameInstance::UPuzzlePlatformsGameInstance()
{
	const ConstructorHelpers::FClassFinder<UUserWidget> MenuBPClass(TEXT("/Game/PuzzlePlatforms/Menu/WBP_MainMenu"));
	MainMenuClass = MenuBPClass.Class;

	const ConstructorHelpers::FClassFinder<UUserWidget> InGameMenuBPClass(TEXT("/Game/PuzzlePlatforms/Menu/WBP_InGameMenu"));
	InGameMenuClass = InGameMenuBPClass.Class;
}

void UPuzzlePlatformsGameInstance::Init()
{
	Super::Init();

	IOnlineSubsystem* Subsystem = IOnlineSubsystem::Get();

	if (Subsystem != nullptr)
	{
		UE_LOG(LogTemp, Warning, TEXT("Subsystem found: %s"), *Subsystem->GetSubsystemName().ToString());
		SessionInterface = Subsystem->GetSessionInterface();
		if (SessionInterface.IsValid())
		{
			SessionInterface->OnCreateSessionCompleteDelegates.AddUObject(
				this, &UPuzzlePlatformsGameInstance::OnCreateSessionComplete);
		}
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("IOnlineSubsystem is null."));
	}
}

void UPuzzlePlatformsGameInstance::LoadMainMenu()
{
	if (!MainMenuClass) { return; }

	MainMenu = CreateWidget<UMainMenu>(this, MainMenuClass);
	if (!MainMenu) { return; }

	MainMenu->Setup();
	MainMenu->SetMenuInterface(this);
}

void UPuzzlePlatformsGameInstance::LoadInGameMenu()
{
	if (!InGameMenuClass) { return; }

	UMenuWidget* InGameMenu = CreateWidget<UMenuWidget>(this, InGameMenuClass);
	if (!InGameMenu) { return; }

	InGameMenu->Setup();
	InGameMenu->SetMenuInterface(this);
}

void UPuzzlePlatformsGameInstance::OnCreateSessionComplete(FName SessionName, bool bSuccess)
{
	if (!bSuccess)
	{
		UE_LOG(LogTemp, Warning, TEXT("Could not create session."));
		return;
	}

	UWorld* World = GetWorld();
	if (World)
		{ World->ServerTravel("/Game/PuzzlePlatforms/Maps/ThirdPersonExampleMap?listen"); }
}

void UPuzzlePlatformsGameInstance::Host()
{
	if (SessionInterface.IsValid())
	{
		FOnlineSessionSettings SessionSettings;
		SessionInterface->CreateSession(0, TEXT("My Session"), SessionSettings);
	}
}

void UPuzzlePlatformsGameInstance::Join(const FString& Address)
{
	APlayerController* Controller = GetFirstLocalPlayerController();
	if (Controller)
	{
		Controller->ClientTravel(Address, ETravelType::TRAVEL_Absolute);
	}
}

void UPuzzlePlatformsGameInstance::LoadMainMenuMap()
{
	APlayerController* Controller = GetFirstLocalPlayerController();
	if (Controller)
	{
		Controller->ClientTravel("/Game/PuzzlePlatforms/Menu/MainMenu", ETravelType::TRAVEL_Absolute);
	}
}

1 Like

Ok. This looks OK. The issue must be in the teardown method.

I assume the set menu interface call is correct and you’ve checked that.add a log to check the interface is set.

Last thing to try is close the editor and delete the binaries folder from your project. It might not be that but sometimes things get messed up and this will trigger a rebuild.

I followed your suggestions but that wasn’t the problem in my case. So I went through all files in the repo to make mine match and realized I had a declaration of IMenuInterface* MenuInterface; in InGameMenu.h . Not sure how it got there, but it seems that it was shadowing the declaration in MenuWidget.h because removing it made the Quit button work.

1 Like

Glad you got it sorted.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.