I created a UObject class named MasterHUD to deal with every UI in the game. It’s a multiplayer game so this is created locally on the client using the character. I’m calling a function that Initialize the HUD. Problem is, everytime I execute CreateWidget, the widget reference always end up in a ACCESS_VIOLATION Error.
[2018.08.15-15.04.45:673][ 35]LogWindows: Error: Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x000000a8
[2018.08.15-15.04.45:673][ 35]LogWindows: Error:
[2018.08.15-15.04.45:673][ 35]LogWindows: Error: [Callstack] 0x00007ffa75b3bec2 UE4Editor-CoreUObject.dll!UnknownFunction []
[2018.08.15-15.04.45:673][ 35]LogWindows: Error: [Callstack] 0x00007ffac83888e8 UE4Editor-Netherworld-2270.dll!FSoftObjectPtr::LoadSynchronous() [c:\program files\epic games\ue_4.20\engine\source\runtime\coreuobject\public\uobject\softobjectptr.h:51]
[2018.08.15-15.04.45:673][ 35]LogWindows: Error: [Callstack] 0x00007ffac83885cc UE4Editor-Netherworld-2270.dll!UMasterHUD::InitHUD() [c:\users\alexa\documents\netherworld\source\netherworld\masterhud.cpp:35]
[2018.08.15-15.04.45:673][ 35]LogWindows: Error: [Callstack] 0x00007ffac838ab33 UE4Editor-Netherworld-2270.dll!AMyGameCharacter::CreateHUD() [c:\users\alexa\documents\netherworld\source\netherworld\netherworldcharacter.cpp:94]
I tried so many things and it has been 2 days now that I’m working on this little feature of a UI Manager. Here is my code:
MasterHUD.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "Blueprint/UserWidget.h"
#include "Components/WidgetComponent.h"
#include "MasterHUD.generated.h"
/**
*
*/
USTRUCT(BlueprintType)
struct FPlayerUI {
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
APlayerController* playerController = NULL;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UUserWidget* PauseMenu = NULL;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UUserWidget* InventoryMenu = NULL;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UUserWidget* InGameHUD = NULL;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool displayingPauseMenu = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool displayingInventoryMenu = false;
FPlayerUI()
{
playerController = NULL;
PauseMenu = NULL;
InventoryMenu = NULL;
InGameHUD = NULL;
bool displayingPauseMenu = false;
bool displayingInventoryMenu = false;
}
FPlayerUI(APlayerController* pc, UUserWidget* pm, UUserWidget* im, UUserWidget* hud)
{
playerController = pc;
PauseMenu = pm;
InventoryMenu = im;
InGameHUD = hud;
bool displayingPauseMenu = false;
bool displayingInventoryMenu = false;
}
};
UCLASS(Blueprintable, BlueprintType)
class NETHERWORLD_API UMasterHUD : public UObject
{
GENERATED_UCLASS_BODY()
public:
UMasterHUD();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
TAssetSubclassOf<class UUserWidget> refPauseMenu;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
TAssetSubclassOf<class UUserWidget> refInventoryMenu;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
TAssetSubclassOf<class UUserWidget> refInGameHUD;
UFUNCTION(BlueprintCallable, Category = Game)
void InitHUD(APlayerController* playerController);
UFUNCTION(BlueprintCallable, Category = Game)
void DisplayPauseMenu(APlayerController* playerController);
UFUNCTION(BlueprintCallable, Category = Game)
bool DisplayInventoryMenu(APlayerController* playerController);
private:
TArray<FPlayerUI*> playerUIs = TArray<FPlayerUI*>();
void DisplayMenu(class UUserWidget* widget, bool display);
FPlayerUI* FindPlayerUI(APlayerController* playerController);
};
MasterHUD.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MasterHUD.h"
#include "Logger.h"
#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h"
UMasterHUD::UMasterHUD(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
ConstructorHelpers::FClassFinder<UUserWidget> newInGameHUDClassRef(TEXT("/Game/UI/InGameHUD"));
if (newInGameHUDClassRef.Class) {
refInGameHUD = newInGameHUDClassRef.Class;
}
ConstructorHelpers::FClassFinder<UUserWidget> newInventoryClassRef(TEXT("/Game/UI/Inventory"));
if (newInventoryClassRef.Class) {
refInventoryMenu = newInventoryClassRef.Class;
}
ConstructorHelpers::FClassFinder<UUserWidget> newPauseMenuClassRef(TEXT("/Game/UI/PauseMenu"));
if (newPauseMenuClassRef.Class) {
refPauseMenu = newPauseMenuClassRef.Class;
}
}
void UMasterHUD::InitHUD(APlayerController* pc)
{
if (!pc)
{
ULogger::LogMessage("Error, trying to init a HUD of a null player controller");
return;
}
// CREATING MENUS
FPlayerUI* newPlayerUI = new FPlayerUI(pc,CreateWidget<UUserWidget, APlayerController>(pc, refPauseMenu.LoadSynchronous()),
CreateWidget<UUserWidget, APlayerController>(pc, refInventoryMenu.LoadSynchronous()),
CreateWidget<UUserWidget, APlayerController>(pc, refInGameHUD.LoadSynchronous()));
// SET DISPLAY OPTIONS PAUSE MENU
newPlayerUI->PauseMenu->AddToViewport(3);
newPlayerUI->PauseMenu->SetVisibility(ESlateVisibility::Hidden);
newPlayerUI->displayingPauseMenu = false;
// SET DISPLAY OPTIONS INVENTORY MENU
newPlayerUI->InventoryMenu->AddToViewport(2);
newPlayerUI->InventoryMenu->SetVisibility(ESlateVisibility::Hidden);
newPlayerUI->displayingInventoryMenu = false;
// SET DISPLAY OPTIONS IN GAME HUD
newPlayerUI->InGameHUD->AddToViewport(1);
newPlayerUI->InGameHUD->SetVisibility(ESlateVisibility::Visible);
playerUIs.Add(newPlayerUI);
ULogger::LogMessage("HUD Initialised");
}
void UMasterHUD::DisplayPauseMenu(APlayerController* playerController)
{
FPlayerUI* currentPlayerUI = FindPlayerUI(playerController);
if (currentPlayerUI->displayingPauseMenu)
{
DisplayMenu(currentPlayerUI->PauseMenu,false);
currentPlayerUI->displayingPauseMenu = false;
}
else
{
DisplayMenu(currentPlayerUI->PauseMenu,true);
currentPlayerUI->displayingPauseMenu = true;
}
}
bool UMasterHUD::DisplayInventoryMenu(APlayerController* playerController)
{
FPlayerUI* currentPlayerUI = FindPlayerUI(playerController);
if (currentPlayerUI->displayingInventoryMenu)
{
DisplayMenu(currentPlayerUI->InventoryMenu,false);
currentPlayerUI->displayingInventoryMenu = false;
}
else
{
if (currentPlayerUI->displayingPauseMenu)
return false;
DisplayMenu(currentPlayerUI->InventoryMenu, true);
currentPlayerUI->displayingInventoryMenu = true;
}
return true;
}
void UMasterHUD::DisplayMenu(UUserWidget* widget, bool display)
{
if (display)
widget->SetVisibility(ESlateVisibility::Visible);
else
widget->SetVisibility(ESlateVisibility::Hidden);
}
FPlayerUI* UMasterHUD::FindPlayerUI(APlayerController * playerController)
{
for (size_t i = 0; i < playerUIs.Num(); i++)
{
if (playerUIs[i]->playerController == playerController)
return playerUIs[i];
}
return new FPlayerUI();
}
Here is the function that calls the creation of the manager and the Init Function
void AMyGameCharacter::CreateHUD()
{
FStringAssetReference bpRef = "Blueprint'/Game/Blueprint/MasterHUD_BP.MasterHUD_BP'";
UObject* bpInstance = bpRef.ResolveObject();
UBlueprint* result = Cast<UBlueprint>(bpInstance);
FActorSpawnParameters SpawnInfo;
hud = GetWorld()->SpawnActor<UMasterHUD>(result->GetClass(), SpawnInfo);
hud->InitHUD(localPlayerController);
}
I’ll try to be more specific. The problem is on my variables similar to refPauseMenu. Whatever I do, the reference is not right. Everything crashes instantly when I used it. At the start the reference was set in the child blueprint, now I set it in the constructor…still crashes.