Blueprint structure can't be correctly saved (serialized)

I’m using the Archive class to implement a save game system. My goal is to serialize any actor and its variables which enable the SaveGame property flag.

So I made an Archive inherits FObjectAndNameAsStringProxyArchive and set ArIsSaveGame to true, and I can enable the SaveGame of any varialbe and they are serialized.

But I found that this works inappropriate for the variables of Blueprint structure type. Even if I check the SaveGame for it, the members are not serialized.

My codes are like below:

struct FVRSaveGameArchive : public FObjectAndNameAsStringProxyArchive
{
    FMySaveGameArchive(FArchive& InInnerArchive)
        : FObjectAndNameAsStringProxyArchive(InInnerArchive, true)
    {
        ArIsSaveGame = true;
    }
};

FMemoryWriter MemoryWriter(record.data, true);
FMySaveGameArchive Ar(MemoryWriter);
actor->Serialize(Ar);

In this way all primitive type (integer, float…etc.) variables are saved correctly, but Blueprint structure type variables are not.

Actually I found that the problem is here:

bool UProperty::ShouldSerializeValue( FArchive& Ar ) const
{
	if (Ar.ShouldSkipProperty(this))
		return false;

	if (Ar.IsSaveGame() && !(PropertyFlags & CPF_SaveGame))
		return false;

	static uint64 SkipFlags = CPF_Transient | CPF_DuplicateTransient | CPF_NonPIEDuplicateTransient | CPF_NonTransactional | CPF_Deprecated | CPF_DevelopmentAssets;
	if (!(PropertyFlags & SkipFlags))
		return true;

If my archive is Ar.IsSaveGame() == true, then the propery must be CPF_SaveGame enabled, however the Blueprint structure properties are not enabled, so they can’t be saved. So I think UE should provide the way to enable CPF_SaveGame for BP structure properties.

Bump! Would like to know if Is this is intended/future work/won’t fix/real bug, thanks!

Hey,

Here is more information on serializing a struct:

https://wiki.unrealengine.com/Save_System,Read%26_Write_Any_Data_to_Compressed_Binary_Files#Overloading_the_.3C.3C_Operator

Hi:
Thanks for the link, I’ve already know that, and my question is about to serialize a Blueprint struct, not CPP struct. The question is how to serialize a Blueprint struct when Archive is set to ArIsSaveGame == true.

Hey,

When it comes to saving Blueprint structs, I suggest following along with: [https://docs.unrealengine.com/latest/INT/Gameplay/SaveGame/Blueprints/][1]

Here are some screenshots of what I did:

[Save Struct]

[Load Struct]

And then, Print out for the Save Struct:

Finally, the Print out for loading what was saved:

If you are still having issues, update your post with what your problem is.

– Follow up

This works the same way in C++

CSaveGame.h

#pragma once

#include "GameFramework/SaveGame.h"
#include "CSaveGame.generated.h"

// Structure that is exposed to BP
USTRUCT(BlueprintType)
struct FTestStruct
{
	GENERATED_USTRUCT_BODY();

	UPROPERTY(BlueprintReadWrite)
	bool BoolVar;
	UPROPERTY(BlueprintReadWrite)
	int IntVar;
	UPROPERTY(BlueprintReadWrite)
	float FloatVar;
	UPROPERTY(BlueprintReadWrite)
	uint8 ByteVar;
	UPROPERTY(BlueprintReadWrite)
	FVector VectorVar;
	UPROPERTY(BlueprintReadWrite)
	FRotator RotatorVar;
	UPROPERTY(BlueprintReadWrite)
	FTransform TransformVar;
	UPROPERTY(BlueprintReadWrite)
	FString StringVar;
};

UCLASS()
class AH452892_API UCSaveGame : public USaveGame
{
	GENERATED_BODY()
	
public:
	UCSaveGame( );

	// ID for save game
	int UserId;

	// Slot name for save game
	FString SaveSlotName;
	
	// Data to save
	FTestStruct SavedTestStruct;	
};

CSaveGame.cpp

#include "AH452892.h"
#include "CSaveGame.h"

UCSaveGame::UCSaveGame( )
{
    // These can change and probably should with more complex games
	UserId = 1;
	SaveSlotName = FString( "UCSaveGame" );
}

SerializeActor.h

#pragma once

#include "GameFramework/Actor.h"

// Need CSaveGame for FtestStruct
#include "CSaveGame.h"

#include "SerializeActor.generated.h"

UCLASS()
class AH452892_API ASerializeActor : public AActor
{
	GENERATED_BODY()
	
public:	
	ASerializeActor();

	virtual void BeginPlay() override;

	// Local TestStruct data
	UPROPERTY(BlueprintReadWrite, SaveGame)
	FTestStruct TestStruct;

	// Save data to SaveGameObject
	UFUNCTION( BlueprintCallable, Category = "Save|Save Test Struct" )
	bool SaveTestStruct( FTestStruct In );

	// Load data from SaveGameObject
	UFUNCTION( BlueprintCallable, Category = "Save|Load Saved Test Struct" )
	FTestStruct LoadTestStruct( );
	
private:
	// Save game object
	USaveGame *SaveGameObject;
};

SerializeActor.cpp

#include "AH452892.h"
#include "SerializeActor.h"

ASerializeActor::ASerializeActor()
{
	// No need for this to tick
	PrimaryActorTick.bCanEverTick = false;
}

// On load
void ASerializeActor::BeginPlay()
{
	Super::BeginPlay();
	
	// Create SaveGameObject
	SaveGameObject = UGameplayStatics::CreateSaveGameObject( UCSaveGame::StaticClass( ) );
}

// Save test struct to our SaveGame
bool ASerializeActor::SaveTestStruct( FTestStruct In )
{
	if( SaveGameObject )
	{
		UCSaveGame *RealSaveGame = Cast<UCSaveGame>( SaveGameObject );
		if( RealSaveGame )
		{
			RealSaveGame->SavedTestStruct = In;
			return UGameplayStatics::SaveGameToSlot( RealSaveGame, RealSaveGame->SaveSlotName, RealSaveGame->UserId );
		}
	}
	return false;
}

// Load test struct from our SaveGame
FTestStruct ASerializeActor::LoadTestStruct( )
{
	if( SaveGameObject )
	{
		UCSaveGame *RealSaveGame = Cast<UCSaveGame>(SaveGameObject);
		if( RealSaveGame )
		{
			TestStruct = RealSaveGame->SavedTestStruct;
		}
	}

	return TestStruct;
}

After creating a child Blueprint class of SerializeActor, this is the Blueprint to save and load the Struct:

Hi:
Thanks for the very detailed answer, I really appreciate it. But please note one very important point, I am using my custom FArchive to do the serialization, which is different with the default one used by UGameplayStatics’s functions. My custom FArchive has set Ar.IsSaveGame to true, which leads to another way of the execution, so in that way the BP struct can’t be saved properly.

Please check this link link text, the 14 upvoted answer. My custom FArchive is like the FFortniteSaveGameArchive example, and with it I can’t save BP struct.

Hi, I’ve exactly the same problem. The issue seems to be that the SaveGame flag is not inherited from struct members.

I hope that behavior will be fixed in the future but in the meanwhile instead of structs I’m using classes that inherits from Object and containing only public members. That works fine and moreover it’s possible to set save / transient flags on each ‘class’ member.

I have the same problem :slight_smile:

Same problem and we may need a issue number to track this

If you are having an issue where the answer here isn’t related, please make a new post in Bug Reports and give detailed steps on how to reproduce it. Here is a guideline on how to write up an issue:

https://answers.unrealengine.com/questions/12363/how-do-i-report-a-bug.html

Thanks.

Coming back to this problem again this month;
For my projects I solved this issue by completely discarding use of FArchive classes and avoiding the Serialize() methods.

I’ve created my own serializer based on UProperty reflection + JSON to replace the ProxyArchive class.
Now I can finally read/write to structs created as Blueprint assets (user defined structs).

Still not fixed in 2019, unfortunately :frowning:

fixed in 2022 :wink: although since I’m here it might be worth to mention that each field of struct in it’s properties has to have ‘save game’ checked, setting it only on struct field is not enough.