x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Office Holiday

Epic Games' offices will be on holiday from June 22nd to July 7th. During this period support will be limited. Our offices will reopen on Monday, July 8th. 

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: https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Engine/UGameInstance/index.html

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?

Product Version: UE 4.10
Tags:
more ▼

asked Dec 29 '15 at 02:58 PM in C++ Programming

avatar image

Gorlock
21 1 7 8

avatar image Doug E ♦♦ STAFF Dec 29 '15 at 08:41 PM

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

Doug Wilson

avatar image Gorlock Dec 30 '15 at 03:58 AM

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.

avatar image TTaM Dec 30 '15 at 12:03 PM
 You should use Cast<Type>( 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 ?

avatar image Doug E ♦♦ STAFF Dec 30 '15 at 01:30 PM

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

avatar image Gorlock Dec 31 '15 at 04:25 AM

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.

avatar image Doug E ♦♦ STAFF Dec 31 '15 at 04:43 PM

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?

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

3 answers: sort voted first

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 Doug for your patience and dedication to this forum. I will don my dunce cap now.

more ▼

answered Jan 08 '16 at 03:24 AM

avatar image

Gorlock
21 1 7 8

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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

more ▼

answered Dec 29 '15 at 03:43 PM

avatar image

TTaM
1.7k 80 28 81

avatar image TTaM Dec 29 '15 at 08:48 PM

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.

avatar image Gorlock Dec 31 '15 at 03:55 AM

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

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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.

more ▼

answered Jan 05 '16 at 05:19 PM

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question