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!