Std::map doesn't copy to play in editor PIE / TMap

I’m trying to make a navigation graph from edges.
At the moment, my class is set up like this:

  1. I have an actor set up to create the std::map, and to tick in both the editor and during play.
  2. In its OnConstruction method I have it call a Test() function.
  3. This adds 4 AVASFVVolume actors to the world, and adds edges to the std::map representing the connections between them.

When I am in the editor, the tick function draws the connections in the world (with DrawDebugLine) as I expect. However, when in PIE the debug lines do not get drawn, and a UE_LOG shows that the size of the map is 0.

I’m using an std::map with Key as a tuple (using the boost library) defining the two connected nodes and the map’s Value being the cost of the connection (using this as a tutorial: Tuples as Map Keys [C++/Boost] - YouTube).

In VolumeNavigator.h I have:

typedef boost::tuple<AVASFVVolume*, AVASFVVolume*> EdgeTuple;

struct EdgeStruct : public EdgeTuple
	{
		EdgeStruct(const EdgeTuple& tuple) : EdgeTuple{ tuple } {}
		AVASFVVolume* volumeA() const { return get<0>(); }
		AVASFVVolume* volumeB() const { return get<1>(); }
	};
	
std::map<EdgeStruct, float> edgeMap;

When an edge is made between two nodes, I am incrementing an int32 as well to denote the size of the std::map. This value gets copied (?) correctly when switching to PIE. But it seems that the std::map doesn’t? Is that because I’m using std::map instead of TMap?

Editor:

PIE:

If that’s the case, has anyone had success in using TMap with a tuple as the key? Switching just the type of my edgeMap causes a lot of compilation errors.

Two things. The constructor for actors isn’t always called when the game starts. It might be called when the actor is serialized. You want to put your thing in PostInitializeComponents or maybe BeginPlay

Second, Yes you should switch it to a TMap. You should try to use the unreal types as much as possible. They have wrappers for almost every stl type that you’d need, except they have added functionality specifically to support engine features.

I’ve modified my code so that now I use a TMap instead of std::map, and managed to remove the dependency on the boost library for tuples as well.

I’m still having the problem though that the TMap with a struct Key, which has pointers to two AActors is not copying into ‘PIE’ or simulation mode.

I’ve set my VolumeNavigator class to tick in both editor and play mode, and in the tick function to try and draw debug lines between every two AActors in the struct. But the debug lines only draw in editor mode and not in play mode. A UE_LOG confirms the .Num() of the TMap is 0 during play.

Why might that be?

Where are you filling the map?

Thanks for replying!

At a high level, I’m trying to connect actors together in a TMap to represent a connected graph of volumes (for an alternative AI navigation idea)

I made a few changes yesterday,

When my first actor spawns, in its BeginPlay function it calls my function Test().

Test adds 4 actors to the world, and fills the TMap. The custom struct is a list of 2 actors and looks like this:
struct edgeStruct
{
AVASFVVolume* edgeTuple[2];

		AVASFVVolume* volumeA() const { return edgeTuple[0]; }
		AVASFVVolume* volumeB() const { return edgeTuple[1]; }

		bool operator==(const edgeStruct& other) const
		{
			return (edgeTuple[0] == other.edgeTuple[0]) && (edgeTuple[1] == other.edgeTuple[1]);
		}

		friend FORCEINLINE uint32 GetTypeHash(const edgeStruct& edge)
		{
			return FCrc::MemCrc_DEPRECATED(&edge, sizeof(edgeStruct));
		}
	};

The first actor is set to tick in both the editor and during PIE and to log the .Num of the TMap to show me how many elements are in it.

When I drag the actor into the world, Test() doesn’t get called and so I get a log that there are 0 elements. When I hit play, the actors get created and added to the TMap as expected, and the log shows there are elements in the TMap and the tick function can draw debug lines between the actors. As soon as I stop the game though the tick log shows 0 elements and the debug lines are no longer drawn.

Ideally, I would like the secondary actors to be created once the first actor is dragged into the level in the editor, for the TMap to be filled at that time, and for the TMap and actors to remain when the level is played.

Ideally, I would like the secondary actors to be created once the first actor is dragged into the level in the editor, for the TMap to be filled at that time, and for the TMap and actors to remain when the level is played.

Hmmm. That’s tricky. Essentially what you want is for an actor instance to spawn other actor instances when you add it to your level. I’m not certain of a good way to do that. I’m sure it’s possible, but I’m not sure of the best way.

If you look in Actor.h/.cpp and look at everything that’s wrapped with the WITH_EDITOR define, you should get an idea of some things that might point you in the right direction. I think what I’ve done in the past for similar situations is to add the other actors separately and then just add them as references to the first actor.

edit: Might be worth trying the forums too.

Thanks for the tips!

@Jayae by any chance did you solve your problem …? I’m trying to do something very similar - have some dynamic things replicated to the editor - and failing terribly.