Crash with TArray of custom struct

I’m attempting to keep track of some data in my game per player in a networked instance.
I have a lobby of sorts where a player can select a character, and I store that data with this struct:

USTRUCT()
struct FPlayerSelections
{
	GENERATED_USTRUCT_BODY()

	//UPROPERTY()
		int32 PlayerID;

	//UPROPERTY()
		FString PlayerName;

	//UPROPERTY()
		EShipItCharacters SelectedCharacter;

	//Constructor
	FPlayerSelections()
	{
		PlayerID = -1;
		PlayerName = "";
		SelectedCharacter = EShipItCharacters::Unknown;
	}

};

My game instance class is where I’m holding an array of this struct:

UCLASS()
class SHIPIT_API UShipItGameInstance : public UGameInstance
{
	GENERATED_BODY()

private:
	
	TArray<FPlayerSelections> CharacterSelections;
};

My crash comes in where I’m trying to add an element to the array:

bool UShipItGameInstance::AddNewPlayerSelectionElement(FPlayerSelections _NewElement)
{

	CharacterSelections.Push(_NewElement);
	return true;
}

In the debugger, I’m seeing the selections array as “Invalid.” Am I missing a proper initialization? I’ve tried CharacterSelections.Init() with and without data and I still get the same crash.

Here’s the relevant portion of the callstack

 	UE4Editor-Core.dll!scalable_msize(void * ptr) Line 2615	C++
>	UE4Editor-Core.dll!FMallocTBB::Realloc(void * Ptr, unsigned __int64 NewSize, unsigned int Alignment) Line 70	C++
 	UE4Editor-Core.dll!FHeapAllocator::ForAnyElementType::ResizeAllocation(int PreviousNumElements, int NumElements, unsigned __int64 NumBytesPerElement) Line 344	C++
 	UE4Editor-ShipIt.dll!TArray<FPlayerSelections,FDefaultAllocator>::Emplace<FPlayerSelections const & __ptr64>(const FPlayerSelections & <Args_0>) Line 1735	C++
 	UE4Editor-ShipIt.dll!UShipItGameInstance::CreateOrUpdatePlayerSelection(FPlayerSelections _NewElement) Line 60	C++
 	UE4Editor-ShipIt.dll!AShipItGameMode::VerifyCharacterChange(TSubclassOf<AShipItCharacter> _CharacterClass, int _PlayerID, AActor * _SpawnTransform) Line 61	C++
 	UE4Editor-ShipIt.dll!AShipItPlayerController::ClientRequestCharacterChange_Implementation(TSubclassOf<AShipItCharacter> _CharacterClass, int _PlayerID, AActor * _SpawnTransform) Line 34	C++

Update: 12/30/15

I think I’m getting closer. (I only get maybe an hour a day to work on this, so going is slow heh) I’ve simplified the code a lot to isolate the problem.

There’s a series of events involved, and I’m beginning to realize that may be the root of my problem, so here’s the entire flow:

I have the following objects involved:
ShipItGameInstance
ShipItGameMode
ShipItPlayerController

ShipItGameInstance

bool UShipItGameInstance::UpdatePlayerSelection(FPlayerSelections _UpdatedElement)
{
	for (int i = 0; i < CharacterSelections.Num(); i++)
	{
		if (CharacterSelections[i].PlayerID == _UpdatedElement.PlayerID)
		{
			CharacterSelections[i] = _UpdatedElement;
			return true;
		}
	}

	return false;
}

void UShipItGameInstance::CreateOrUpdatePlayerSelection(FPlayerSelections _NewElement)
{
	if (!UpdatePlayerSelection(_NewElement))
	{
		CharacterSelections.Add(_NewElement);
	}
}

ShipItPlayerController

In ShipItPlayerController, I have this function which sets things off in motion. In our game, players can change their character on the fly so this event sends off a request to the server to change characters.

void AShipItPlayerController::ClientRequestCharacterChange_Implementation(TSubclassOf<AShipItCharacter> _CharacterClass, int32 _PlayerID, AActor* _SpawnTransform)
{
	//Check if params are actually filled
	if (_CharacterClass == NULL || _PlayerID == NULL || _SpawnTransform == NULL)
	{
		UE_LOG(LogTemp, Error, TEXT("ClientRequestCharacterChange_Implementation param is null. Character request failed. Character Class %s, Player ID %d, SpawnTransform %s"), *_CharacterClass, _PlayerID, _SpawnTransform);
		return;
	}

	//Check if we can use the ship it game mode
	AShipItGameMode* gameModeRef = (AShipItGameMode*)GetWorld()->GetAuthGameMode();

	if (gameModeRef == NULL)
	{
		UE_LOG(LogTemp, Error, TEXT("Game ref couldn't cast to ship it game mode. What game mode are you using?"));
	}
	else
	{
		//Send character change request over to game mode
		gameModeRef->VerifyCharacterChange(_CharacterClass, _PlayerID, _SpawnTransform);
	}
}

ShipItGameMode

Game mode then tries to fulfill the character change request. This may be the wrong place to put the code, but it’s what came to mind first I guess.

void AShipItGameMode::VerifyCharacterChange(TSubclassOf<AShipItCharacter> _CharacterClass, int32 _PlayerID, AActor* _SpawnTransform)
{
	UE_LOG(LogTemp, Log, TEXT("VerifyCharacterChange running on server"));

	//Save to the gameinstance the character that this player has chosen
	UShipItGameInstance* ShipitGameInstance = (UShipItGameInstance*)GetGameInstance();

	if (ShipitGameInstance != NULL)
	{
		FPlayerSelections newPlayerSelection;
		newPlayerSelection.PlayerID = 100;
		newPlayerSelection.PlayerName = "TESTPLAYERNAME";
		newPlayerSelection.SelectedCharacter = EShipItCharacters::Swordsman;
		ShipitGameInstance->CreateOrUpdatePlayerSelection(newPlayerSelection);   //crashes when called here
	}
}

The Crash

The crash only happens when CreateOrUpdatePlayerSelection() is called from game mode. When running the debugger, I get a break when I first run the editor, and I can see the TArray is valid and an element is added. When I hit a breakpoint as it’s being called from game mode, it’s listed as “invalid.”

My questions thusfar

When I run a debug instance, I get a breakpoint in the constructor for gameinstance immediately. This is expected from the documentation. I can add an element to the array just fine at this point. I’m NOT getting a breakpoint when I run a new PIE instance - I am expecting to get one based on the documentation here: UGameInstance | Unreal Engine Documentation

Seeing as the gameinstance object code is running, and crashing, I know I have a reference to AN instance somewhere. What could be making this gameinstance’s member variables invalid?

Have you tried .Add instead of .Push? I guess it won’t make a difference, but you never know.

This is also the sort of thing you’d get if the game instance you’re calling your method on was null or just generally an invalid pointer.

Hey Gorlock-

Where are you calling the AddNewPlayerSelectionElement() function? Are you passing in a specific instance of the struct or an element of an array of FPlayerSelections’. Calling the function with a specific instance of FPlayerSelections was able to succeed without a crash.

Cheers

Good call. I’ve run down to the simplest test possible and ran:

FPlayerSelections newPlayerSelection;
	newPlayerSelection.PlayerID = 100;
	newPlayerSelection.PlayerName = "PlayerName";
	newPlayerSelection.SelectedCharacter = EShipItCharacters::Unknown;

	CreateOrUpdatePlayerSelection(newPlayerSelection);

in my constructor. Everything works fine here, so there’s obviously something else at hand.

When I run this same process from my game mode class, I get the crash. The code there is as follows:

UShipItGameInstance* ShipitGameInstance = (UShipItGameInstance*)GetGameInstance();

FPlayerSelections newPlayerSelection;
						newPlayerSelection.PlayerID = -100;
						newPlayerSelection.PlayerName = "TESTPLAYERNAME";
						newPlayerSelection.SelectedCharacter = EShipItCharacters::Swordsman;

ShipitGameInstance->CreateOrUpdatePlayerSelection(newPlayerSelection);

I’ve trimmed the code here for easy reading, but I have null checks in place for gameinstance and other stuff here.

You should use Cast( Object ); with UObjects - Or CastChecked. C-style casts are bad in general.

It’s possible that when the engine loads the map, it creates the game mode before assigning the world to it properly. Have you tried putting that code in BeginPlay (does this even run on GameMode?) or HandleMatchIsWaitingToStart ?

What function is the code in your game mode being added to? Additionally, the code here seems to call a function named “CreateOrUpdatePlayerSelection()” however your original post mentioned the function “AddNewPlayerSelectionElement()”, how do these functions relate to each other? Can you also let me know if TTaM’s suggestion of changing the cast format helps? W

I have tried both. Unfortunately did not solve the problem. Thank you though!

Updated the original post. I have tried the different cast method - this actually consistently failed where the original method succeeded.

I thought I was running into a TArray problem originally, but I’m seeing now it’s definitely something else so I’ve included all relevant functions in the main post now.

Is the ShipItGameMode the default class that is created with the project or is it a custom class that was added? Can you walk me through the steps of your setup? If you’re able to recreate this crash in a new project can you list the steps/setup that cause it to happen? Additionally can you post the full callstack and the log files from when the crash occurred?

Hi Gorlock,

We have not heard back from you in a few days, so we are marking this post as Resolved for tracking purposes. If you are still experiencing the issue you reported, please respond to this message with additional information and we will offer further assistance.

Thank you.

I am so ashamed.

I forgot to add my game instance class to the defaultengine.ini.

[URL]
[/Script/EngineSettings.GameMapsSettings]
GameInstanceClass=/Script/ShipIt.ShipItGameInstance

Thank you for your patience and dedication to this forum. I will don my dunce cap now.