GetWorld()->GetAuthGameMode() access violation

Hi, im having a crash (access violation):

when i try to access

Cast<AMyGameMode>(GetWorld()->GetAuthGameMode())->InventoryManager->AddItemToInventory(this);

the crash happen when i try to GetWorld()->GetAuthGameMode()

Why is this happening? Why i dont have the reference to the game mode?
I am calling the function that contain the lines above from a UMG Widget class.
Is a singleplayer game (no server and clients)

Could i provide more info?
thanks !

So if you are actually the server (which should be the case in a single player game) then I would advice to break the line down and debug each statement.

It could fail to cast the GameMode.
GetWorld() could return NULL.
Inventory Manager could also be NULL at the time.

Yes, sorry for my English i think I did not write clearly.
The fail is when i try to get the Game mode.

exactly here:
GetWorld()->GetAuthGameMode();

Then check if GetWorld() returns a valid UWorld object.


UWorld* world = GetWorld();
if(world)
{
world->GetAuthGameMode();
}


Because you can’t be certain that it will return a valid value everytime.

Ok, i will check that, but, if it doesn’t return a valid value, what can i do?, i need the gamemode to access my “InventoryManager”.
I mean:


UWorld* world = GetWorld();
if(world)
{
world->GetAuthGameMode();
}
else{
 //Could i do something here??
}

thanks for your answers :slight_smile:

If it does not return a valid value, you might call it too early after game initialization (for example in the constructor).

The solution is just to push it into a later stage. Maybe PostInitializeComponents() or BeginPlay().

Ok, i think i know what could be the problem.
I’m creating instances of “AItem” this way:


GetDefaultObject()

Because some items are never spawned on the world. (I access a “loot” container that create a widget, and showing the items in that widget, so i create a reference of the item in that widget)

hope you understand what i’m saying :slight_smile:

Could this be the problem?

EDIT:
I create a video (because my English sucks i think this way is best understood

so when i hit “Take” the crash happen.

And this is when i “interact” with the white box.



void AContainerLoot::Interact(){
	//This is firing here because I dont want the container store the data if the player never interact with it
	if (ItemsInContainer.Num() == 0){
		//Cantidad de items en container
		int32 itemsQuantity = FMath::RandRange(0, 3);
		if (itemsQuantity > 0){
			ASurvivalGameMode* ASGM = Cast<ASurvivalGameMode>(GetWorld()->GetAuthGameMode());
			for (int32 i = 0; i < itemsQuantity; i++){
				int32 randomIndex = FMath::RandRange(0, (ASGM->InventoryManager->GetItemDataBaseSize() - 1));
				ItemsIndex.Add(randomIndex);
				TSubclassOf<AItem> item = ASGM->InventoryManager->ItemDB->GetItemById(randomIndex);
				if (ASGM->InventoryManager->ItemDB->GetItemById(randomIndex) != NULL){
					ItemsInContainer.Add(item);
				}

			}
		}
	}

	if (ItemsInstancesInLoot.Num() == 0){
		for (int32 i = 0; i < ItemsInContainer.Num(); i++){
			ItemsInstancesInLoot.Add(ItemsInContainer*.GetDefaultObject());
		}
	}

	//This is implemented on BP
	CreateLootWidget();

}

TArray<class AItem *> AContainerLoot::GetItemsInLoot(){
	return ItemsInstancesInLoot;
}


GetItemsInLoot() is called from the blueprint (subclass of the class containing the above Code) and then i pass the “ItemsInstancesInLoot” to the widget.

That might actually be the problem. And it is bad practice to just use GetDefaultObject(). The CDO (Class Default Object) is more like a template object and should not be used for game code directly.

Actors should always be spawned via GetWorld()->SpawnActor() if you want to access them at runtime.

You might already have something like the following, but you should consider encapsulating your ItemClasses for Inventories like this:



USTRUCT()
struct FItemData
{
	GENERATED_USTRUCT_BODY()
         
        /** store the item class */
	UPROPERTY(EditDefaultsOnly, Category = Item)
	TSubclassOf<class AItem> ItemClass;

        /////////////////////////////////////
        // ADDITIONAL ITEM INFORMATION HERE, FOR EXAMPLE ID, DisplayName, UIIcon etc.

	FItemData::FItemData()
        {
              ItemClass = AItem::StaticClass();
	}

};



This way you can pass the items around between inventories without spawning them.

But you have to make sure that as soon as you want to access data in an AItem-Object, you should Spawn it correctly instead of using ItemClass->GetDefaultObject().

Thanks for the info DennyR, really really helpful!
I understand that i have to spawn the actor in order to access data. The weird thing about that is this scenario:
I need to show the “item description” on my UMG widget, so now I need to spawn the item to access that description. So I spawn it always with a location and rotation or transform into the level, **but this item should not exist on the level. ** , that confuses me a bit

Thanks again for your time DennyR, I think I have to study a little =)

What he described in his last post is the way you get around this. You separate the ItemData into it’s own struct that will hold item properties that are required without an actor. While it’s in your inventory you store it as an FItemData, then when you want to spawn the instance of your item into the world you use the ItemClass to spawn an instance and initialize it with the data stored in your FItemData instance (or just store a reference/copy of the FItemData in it). You’re just separating your ItemData from your ItemActor. The ItemActor is the thing that actually appears in the world, and your ItemData is the lightweight version of your item that is what is accessed in inventory and populates the ItemActor with the data it needs.

Sorry if that’s kind of verbal vomitty.

Hi DennyR , sorry to bother you again. I am studying what can i do and I realise that i didn’t understand why i shood encapsulating the ItemClasses.

I will explain what i have:

An ItemDataBase


USTRUCT()
struct FItemData
{
	GENERATED_USTRUCT_BODY()

	UPROPERTY(EditDefaultsOnly, Category = Item)
	TSubclassOf<class AItem> Item;

//Other info that I could need

};

/**
 * 
 */
UCLASS()
class My_API AItemDataBase : public AActor
{
	GENERATED_UCLASS_BODY()

	UPROPERTY(EditDefaultsOnly, Category = ItemDatabase)
	TArray<FItemData> ItemClasses;

	TSubclassOf<class AItem> GetItemByName(FString ItemName);

	TSubclassOf<class AItem> GetItemById(int32 index);
};

And a child blueprint “BPItemDataBase” where i fill with data the TArray “ItemClasses”.

On a “InventoryManager” constructor i just instantiate the Data Base


	static ConstructorHelpers::FObjectFinder<UBlueprint> ItemBDBlueprint(TEXT("Blueprint'/Game/Blueprints/Inventory/BPItemDataBase.BPItemDataBase'"));
	if (ItemBDBlueprint.Succeeded())
	{
		GameItemDataBase = (UClass*)ItemBDBlueprint.Object->GeneratedClass;
		ItemDB = GameItemDataBase->GetDefaultObject<AItemDataBase>();	
	}


And on my GameMode in the BeginPlay function i Spawn the InventoryManager:


void AMyGameMode::BeginPlay(){
	Super::BeginPlay();
	InventoryManager = Cast<AInventoryManager>(GetWorld()->SpawnActor(AInventoryManager::StaticClass()));
}


Then i have a ContainerLoot class, with can hold loot woth a TArray:


	UPROPERTY(EditDefaultsonly, BlueprintReadOnly, Category = ContainerItem)
	TArray<TSubclassOf<class AItem>> ItemsInContainer;

so here i can manually add items to a container or, if it doens’t have any, random populate the “ItemsInContainer” array from the ItemDB like this:


if (ItemsInContainer.Num() == 0){
		
		int32 itemsQuantity = FMath::RandRange(0, 3);
		if (itemsQuantity > 0){
			ASurvivalGameMode* ASGM = Cast<ASurvivalGameMode>(GetWorld()->GetAuthGameMode());
			for (int32 i = 0; i < itemsQuantity; i++){
				int32 randomIndex = FMath::RandRange(0, (ASGM->InventoryManager->GetItemDataBaseSize() - 1));
				ItemsIndex.Add(randomIndex);
				TSubclassOf<AItem> item = ASGM->InventoryManager->ItemDB->GetItemById(randomIndex);
				if (ASGM->InventoryManager->ItemDB->GetItemById(randomIndex) != NULL){
					ItemsInContainer.Add(item);
				}

			}
		}
	}

Now when i interact with this container actor, it should return instances of items wich are in “ItemsInContainer” in order to show the properties like “item descripcion” “item name” “item value” etc to a UMG widget.
SO here is the problem, if i spawn every item in every lootcontainer, i will end up woth a lot of spawned items all around the scene (wich i could hide or set not visible), but they still be there, but i cant find other way to do this.

Hope you / someone understand my problem :slight_smile:
And im sorry for the wall of text

Hey Alexarg, no problem at all. I understand your problem and I already gave an answer to it.
Just go back and read the my last and mrooney’s post. :smiley:

I think it is language barrier thing, so I will try to give it another go on your current state.

You have the lines of code:




/**
 * 
 */
UCLASS()
class My_API AItemDataBase : public AActor
{
	GENERATED_UCLASS_BODY()

	UPROPERTY(EditDefaultsOnly, Category = ItemDatabase)
	TArray<FItemData> ItemClasses;

	TSubclassOf<class AItem> GetItemByName(FString ItemName);

	TSubclassOf<class AItem> GetItemById(int32 index);
};


UPROPERTY(EditDefaultsonly, BlueprintReadOnly, Category = ContainerItem)
TArray<TSubclassOf<class AItem>> ItemsInContainer;


just change it to :



/**
 * 
 */
UCLASS()
class My_API AItemDataBase : public AActor
{
	GENERATED_UCLASS_BODY()

	UPROPERTY(EditDefaultsOnly, Category = ItemDatabase)
	TArray<FItemData> ItemClasses;

	FItemData GetItemByName(FString ItemName);

	FItemData GetItemById(int32 index);
};

UPROPERTY(EditDefaultsonly, BlueprintReadOnly, Category = ContainerItem)
TArray<FItemData> ItemsInContainer;


…so your containers work with the ItemData struct as well. In order to make use of the struct and to avoid spawning items for your inventories, add the information only needed in the inventory to the struct like this:


USTRUCT()
struct FItemData
{
	GENERATED_USTRUCT_BODY()

	UPROPERTY(EditDefaultsOnly, Category = Item)
	TSubclassOf<class AItem> Item;

        //Other info that I could need
        UPROPERTY(EditDefaultsOnly, Category = Item)
        FText DisplayName;

        //Other info that I could need
        UPROPERTY(EditDefaultsOnly, Category = Item)
        FText ItemDescription;

        //Other info that I could need
        UPROPERTY(EditDefaultsOnly, Category = Item)
        float Weight;

        //Other info that I could need
        UPROPERTY(EditDefaultsOnly, Category = Item)
        UTexture* UIIcon;

        //... and whatever you need
};

Then in your AContainerLoot::Interact() function you can just pass the FItemData-Struct instead of the Actor or the ItemClass. In your UI you can then access the FItemData.DisplayName without spawning the Item.

This way you only have to spawn the Item if you want to see it in the game world.

ooooh I feel so stupid!
I understand and it’s true, you had already answered above, just i did not understand, I think your last post was excellent, everything clear now :smiley:
Thanks very much !!!

Glad I could help :slight_smile:

Well, i have the same problem: I need to get my GameMode’s method, so i call a reference from my character, but getting the reference crash the editor, i don’t understand why.

@SalahAdDin

The GameMode is not available to clients in multiplayer. It doesn’t exist. Please don’t bump multiple ancient (+5 year old) threads to ask the same question, create a new thread.