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"

TMap set in Editor and used in PIE

I have a TMap being filled during the editor mode, and I want to use it during PIE. But whenever I try and make an iterator or access it, the game crashes with "Access violation reading location 0x0000000000000000."

I'm using this TMap in a A* navigation system. It stores a struct representing an edge (key of map), and the cost of the edge (element of map).

In beginPlay() during PIE I'm printing to the log the size of edgeMap.Num(), and it says 0. I can retrigger the method to fill it, which then says that edgeMap.Num() is the expected number. But I still get the violation crash.

I read that TMaps still cant be made a UPROPERTY(), but doing that re-filling^ still causes a crash.

I can share more code if it helps. Thanks for looking.

.h

 //outside class definition
 USTRUCT()
 struct FEdgeStruct
 {
     GENERATED_BODY()
 
     UPROPERTY()
         AVASFVVolume* edgeTuple[2];
 
     AVASFVVolume* volumeA() const { return edgeTuple[0]; }
 
     AVASFVVolume* volumeB() const { return edgeTuple[1]; }
 
     FEdgeStruct()
     {
         edgeTuple[0] = NULL;
         edgeTuple[1] = NULL;
     }
 
     FEdgeStruct(AVASFVVolume* volume1, AVASFVVolume* volume2)
     {
         edgeTuple[0] = volume1;
         edgeTuple[1] = volume2;
     }
 
     bool operator==(const FEdgeStruct& other) const
     {
         return (edgeTuple[0] == other.edgeTuple[0]) && (edgeTuple[1] == other.edgeTuple[1]);
     }
 
     friend FORCEINLINE uint32 GetTypeHash(const FEdgeStruct& edge)
     {
         return FCrc::MemCrc_DEPRECATED(&edge, sizeof(FEdgeStruct));
     }
 };
 //then later inside class definition
 TMap<struct FEdgeStruct, float> edgeMap;
Product Version: UE 4.10
Tags:
more ▼

asked Jul 18 '16 at 04:48 PM in C++ Programming

avatar image

Jayae
57 12 18 25

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

2 answers: sort voted first

It's hard to tell what the issue is without more context (e.g. the stack trace of the crash and the code around it), but one possible issue is that you're using a USTRUCT with naked pointers. Unreal treats USTRUCTs differently than UCLASSs, and your AVASFVVolumes and TMap may be reclaimed by the garbage collector before you are done with them.

Check if changing the USTRUCT to UCLASS fixes the issue.

more ▼

answered Jul 18 '16 at 06:27 PM

avatar image

Digi Labs Dan
571 16 12 34

avatar image Jayae Jul 19 '16 at 05:27 PM

Hi! Thanks for helping.

Today I changed my struct to it's own UObject, gotta admit it looks a lot cleaner ha. Because of that, I'm also allowed to make the TMap edgeMap; a UPROPERTY(), without the compiler complaining.

Now I can set up my TMap in the editor, and start PIE, and edgeMap.Num() stays the correct size.

I get to a point in my code though that the TMap is iterated through to find all the neighbouring volumes (the volumeBs). In my A* navigation, a volume might be connected to many other volumes.

What I'm finding though is that when I'm iterating through:

 for (auto It = edgeMap.CreateConstIterator(); It; ++It)
     {
         if (It.Key()->volumeA() == currentVolume) //test both pointers point to the same thing
         {
             neighbours.Add(It.Key()->volumeB());
         }
     }

then It.Key()->volumeA() == currentVolume is never true. Despite the UObject definitely being instantiated and added to the TMap. When I put some debug logging into that loop to print out volumeA's and currentVolume's GetHumanReadableName, they are both the same. But the objects GetUniqueID are different!

The currentVolume is getting assigned during PIE, and is a pointer to a AVASFVVolume. As is volumeA, as you can see in my original struct (now a UObject).

avatar image Jayae Jul 19 '16 at 05:33 PM
avatar image Jayae Jul 19 '16 at 05:54 PM

Not resolved, please dont auto resolve this question Doug-Wilson

avatar image Digi Labs Dan Jul 19 '16 at 07:02 PM

Hmm... I can't see where AVASFVVolume's are created, so I can't confirm these are actually the same object.

I think the gotcha here is that, when you Play-In-Editor, actors are duplicated from the original editor objects (as per UObject::PostDuplicate(bool bDuplicateForPIE)), so somehow your code is checking equality between a pointer to the original actor and a pointer to the duplicated actor.

Is there some other property you could use for checking equality? Could you use some other property (e.g. dimensions or name) for checking equality of AVASFVVolume *?

avatar image Jayae Jul 19 '16 at 07:05 PM

Yep I think there is something I could use instead of pointer equality. Thanks for the tip I'll try that tomorrow!

avatar image Jayae Jul 20 '16 at 04:27 PM

I was able to use the GetHumanReadableName to check equality fine, thanks!

But now I just have the original crashing problem that when I try to use .Add or .Find on the TMap I get Exception thrown: read access violation.

Each AVASFVVolume has a UPROPERTY(EditAnywhere) TArray<AVASFVVolume*> connections; so that you can create the volume-volume connections in the editor (and save the level). Then when PIE begins, all volumes are iterated through and a UNavEdge is created and added to TMap UPROPERTY() TMap<UNavEdge*, float> edgeMap;, but this crashes when the add happens.

Are the AVASFVVolume pointers created in the editor not transformed when PIE begins to be pointers to the duplicated actors? If not, then how could I possibly accomplish a TMap of these connections? If I create the TMap during the editor mode, then it will also be full of editor pointers right?

Thanks for your help

avatar image Digi Labs Dan Jul 20 '16 at 10:53 PM

I'm really clueless, but here's my best guess: When calling NewObject(UNavEdge) you are not specifying an Outer. I don't know the consequences of this, but I do know that ActorComponents are always outered to their actor and that StaticDuplicateObject also copies objects inside the target object. Try providing AVolumeNavigator as the Outer and see if that fixes it.

Another thought, which might be relevant: TMap is a hashing collection. This means that objects are stored in buckets based on their computed hash value. BUT your hash function UNavEdge::GetTypeHash is based on the pointers inside NavEdge. So anything that moves a AVASFVVolume * in memory will invalidate your TMap. Something could be copying your map and its contents without rehashing (which will cause things to be in the wrong bucket) or something is causing your NavEdges to be moved around in memory. It's possible that UObjects are not supported in a UPROPERTY hashing collection --- I can't find any examples of doing this in the engine code.

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

Not resolved, please dont auto resolve this question Doug-Wilson

more ▼

answered Jul 19 '16 at 05:46 PM

avatar image

Jayae
57 12 18 25

(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