Unexpected Behavior: Derived Blueprint Actor from C++ Actor not saving correctly

I have had to revise this issue, for me it is the same issue, but the cause was different than what I though I was experiencing…

Previously if you read this issue, it seemed to be a problem with UObject derived Objects not saving correctly if derived from Blueprinted versions, I was wrong, after much more debuging today after much sleep and relaxation, and with a clearer head, I WAS that Actor not the UObject that was the issue.

As I mentioned it is a close issue, BUT is different enough to ignore the previous Issue but keep the same question open.

So here it is, The UObject I believed to not be saving when used as a Blueprint derived class was in fact saving when using a Native C++ version of the AActor, but not saving when using a Blueprint Derived AActor, infact when using a Blueprint derived version of the AActor neither the Native UObject or the Blueprint Derived class was saving with the AActor, but does save in the editor when using the Native C++ Actor.

The Actor is spawned into the Editor using the SpawnActor(UClass* Class, FVector, FRotator) function.

Class is assigned based on a TSubclassOf that is assigned by the Spawning actor.

So if you read my old, unrevised question you will see that it is in fact very similar, just in reverse order.

I will continue to refine my debuging, but I have no idea why this is happening.

Hi ,

Unfortunately, seeing as you edited your original post, we are unable to view what the original post was so I can’t refer to your original question for a frame of reference.

Can you explain exactly what you mean by ‘not saving correctly’? Does this mean that you are receiving an error about it not being able to save, it just not saving at all, maybe one value isn’t being saved while others are?

As your paragraph about what had problems saving seems to be worded for someone who knows what the original question was, can you specify what is having problems being saved?

Lastly, could you provide me with all of the code related to this issue as the error could be in the code itself?

Original Question:

Unexpected Behavior: NewObject from TSubclassOf
I have hit some unexpected behavior when using NewObject and TSubclassOf to create a subclass of the classtype and saving in the editor.

TSubclassOf userdefinedObjectclass;

NewObject(this, userdefinedObjectclass);

This behavior works fine no matter what type of class is created as long (of course) the class derives from UMainObject (even blueprinted versions work with it) as expected…

When creating these objects in the editor everything will work fine, till you reopen the map/editor.

If you have created the classes using UMainObject (no derived class) the items were saved to the editor and get regenerated correctly and you can continue on your way, BUT if you used say

UCLASS()
class USomeOtherObject : public UMainObject
{
}

and set userdefinedObjectclass to USomeOtherObject and then try to create these objects, they will work fine, until like I said, you save/reload the editor, at which point the derived class isn’t recognized (I assume) and is not regenerated, leaving you with NULL arrays or references.

The Same behavior is seen when trying to use Blueprint generated classes derived from UMainObject, they will load, create, work like a charm in the editor until reloaded, then they as well are NULL.

Some points of interest, this is in a plugin that is set to runtime, the UObjects that are created are placed into a lookup system used with TMaps and TArrays and are part of an AActor (which noted, does not have the same issue as these UObjects, derived versions are saved and reloaded without issue). The reference to the AActor is referenced into another AActor manager type class. Which can be derived as well from extended classes/blueprints. Also note, the AActor references are also placed into a similar lookup system, using the same TArray, TMap setups and saving and loaded works fine with both Derived and Native classes used.

I figured that you would be able to see history and revisions, sorry should have left it before, but I didn’t think about it ;).

The problem is that one set of Arrays is not saved after editing in the editor, I have a UOBject that has a TMap in it, it is not saved if I use the Blueprint derived Actor versus the Native Actor.

From what I understand, this is a very specific bug. The first step is getting a solid method of reproducing the issue. Can you please provide a list of steps that could reproduce this issue? If it depends on your plugin that you’ve created, would it be possible for you to provide that as well? If you are able to provide steps, please see if they are able to reproduce this issue from a blank project.

I will send you the code for the Test project which I have set everything up for testing… here is what I have done, and some additional things I have observed (any I believe this explains the discrepancies I had noticed in my first post compared to my second post)

Things I did to prepare for the code project I am going to send you:

  1. Created a new blank c++ project (added in starter, still needed a few references)
  2. Made BPs of: HexGridManager (C++ Class, AActor) and HexGridActor (C++ Class, AActor) and UHexGridMapInfo (C++ Class, UObject)
  3. Made a controller BP (Base controller class) and set mouse to visible
  4. Made a simple Level BP, this will be included in the project I send you

Below is the Details panel for the Manager class:

https://photos-6.dropbox.com/t/2/AADQdCHBPIBNw2Y6n5XXILCGArxsM3xyr02YtjD3Bb1kNQ/12/68035857/png/32x32/1/_/1/2/Details.png/EMKC8TQY3x4gASgBKAc/dxRP8j0c3lPGyVg21zgK5NpqBseuErAXPoK-dfJ-OzQ?size=1280x960&size_mode=2

Direct Link if Image doesn’t show: Dropbox - Error

Things that need to be set in a new Manager class before use are:

  • Hex Divisions (I prefer 10) 1 is default, if left at one it will create 1 actor per hex (just warning you before you start testing things)
  • Hex Height (this needs to be 200 as thats the size of the testing hexgrid mesh I am using) sorry I have not set the default in code

To get things to update you need to change the size of the grid map with “Grid Size”, open it up and add in numbers, keep them low 10 to 50 (this is the number of hex per side that are generated, max I got it up to is 1024 before melt down) so you understand the numbers can grow fast.

TO BE CONTINUED!!!

To Test:

  • Hit Play In Viewport.
  • Turn till you can see the hexmap in the viewport
  • Put cursor over any part of the hexmap, hit H this will tell you the x,y,z coords of the piece you had your cursor over (important for test: if values are 0,0,0 then the piece info for that hex is NULL, this applies only to hex not at genesis point which will be 0,0,0 naturally) If it is NULL then it was not saved on last editor save and editor restart.

I would recommend that you change the gridsize if this test map, save, and restart the editor, you should see that all the items remain updated, and all hexes report their position correctly.

Now, Change either HexGridPieceMapInfo or HexGridActor to their BP versions (MyHexGridPieceMapInfo or MyHexGridActor), This can be done under the Sub Grid section of the Details panel, and then change the grid size, play, see the hexes show their numbers, stop, save, exit, restart editor… play, you will probably notice that all grids now show as 0,0,0…

This behavior cascades up, if you use MyHexGridPieceMapInfo, hexes info is not saved, MyHexGridActor, use of either MyHexGridPieceMapInfo or Native HexGridPieceMapInfo doesn’t seem to be saved, if you use MyHexGridManager (in place of HexGridManager) the references to MyHexGridActor (or Native HexGridActor) are not saved.

So my observation currently is that Blueprint Actors are either not saving the reference (UPROPERTIES) of the Native underlying class, or it is trying to load the wrong class and aborting the reload on restart (tho no logs seem to indicate this happening)

I will send the entire project to you (the testing project) for you to play with, if you need anymore information feel free to ask, I am not afraid to type.

Hi ,

Thank you for providing so much information and working with me on getting this bug reported. I’ve been able to reproduce the issue without fail and have reported the issue in our database. For your reference, the bug number is UE-19253. Unfortunately, I have no workaround to provide you with at the moment but hopefully we will have it fixed soon.

Have a nice day,

Hi ,

Sorry for the late reply on this, I’ve just now been able take a look at this issue.

What we’re running into here is that UObjects created as default subobjects are not going to be “instanced” by default. This means that we won’t get a unique and separate copy of the subobject when the Actor itself is instanced - instead, it will simply point back to a single shared copy that’s owned by the Actor class default object.

The way you have this coded up, changing the grid size in the details panel is internally triggering a refresh of your AHexGridActor set. I see that this has a ‘PieceMap’ member which is of type UHexGridPieceMap, which is a custom UObject subclass. However, since that member is not explicitly tagged as ‘Instanced’, this line in the AHexGridActor ctor:

// Initialize PieceMap
	PieceMap = CreateDefaultSubobject<UHexGridPieceMap>(TEXT("HexPieces"));

actually results in only a single instance of the UHexGridPieceMap object, owned by the UHexGridPieceMap class default object, and shared by all AHexGridActor instances. Which means then, that when AHexGridActor::AddInstance() is called as a result of changing the grid size, it’s adding to the PieceMap inside the class defaults and not specifically to the selected AHexGridActor instance in the level!

This can be fixed as follows - in HexGridActor.h, simply change this code:

// A Local list of Locations
UPROPERTY(VisibleAnywhere, Category = Grid)
UHexGridPieceMap* PieceMap;

to this instead (add the ‘Instanced’ keyword):

// A Local list of Locations
UPROPERTY(Instanced, VisibleAnywhere, Category = Grid)
UHexGridPieceMap* PieceMap;

and recompile. Now, whenever you create a new AHexGridActor instance, it’ll have its own unique copy of the UHexGridPieceMap! Note that you’ll also need to change the grid size to “refresh” the instanced map - as your first load after recompile will start out with an empty map (it’ll be a unique PieceMap, but it won’t initially contain anything). After that first refresh though, saving the level should persist the unique map state for the next launch of the editor.

Alternatively, in this case we could have simply used NewObject() to create the UHexGridPieceMap, rather than CreateDefaultSubobject(). The latter is intended more for cases where we might only have a small number of differences between the class default object’s copy and the instance’s copy - in that case, the object only serializes its differences and not the full object, resulting in less memory overhead. This is why, for example, UActorComponent types default to being instanced - you don’t necessarily want to have a full serialized set of UActorComponent instances per Actor instance in your level, because most of the time a good chunk of the state will match up with what’s in the class default object, so there’s not really any need to save out the entire object as a unique copy. But in this case, we’ve probably already got a full unique state per subobject instance, so there’s not really a need to do this.

Also as a side note - subclasses of UActorComponent are always treated as ‘Instanced’ by default. This is why it’s not necessary to explicitly add the ‘Instanced’ keyword in the case of the MeshInstance member:

// StaticMesh Holder
	UPROPERTY(VisibleAnywhere, Category = Grid)
	UHierarchicalInstancedStaticMeshComponent* MeshInstance;

Hope this helps!

Hi, thanks for the reply (no matter how old it was). I missed this and just happened to see the extra answer on my profile.