[C++]How To Save Array Of Structs

Hey guys. I have a struct A that stores transform, softclass ptr, string, and TArray. I am using the ObjectAndNameAsStringProxyArchive. I am trying to save an array of struct A but can’t figure out how to. I have a struct B that holds the array and a string. Once all the struct A’s are added to the array in struct B, I want to save struct B to a file. Problem is I can’t figure out how to do this. I can save a single struct A by writing it’s TArray to file but that won’t work in the case of struct B. How would I save struct B to a file? (I already have a file path). I can provide more info if needed. Thank you in advance!

I figured it out. I needed to add a TArray to struct B to act as the bytestream. In struct B, I overloaded the << operator to save to my archive. And then to save, I just set the array, created a FMemoryWriter with the bytestream, and then created the archive and using the overloaded << operator, I saved to the archive. And finally, I wrote the bytestream to the file.

Hi! You can do this is several steps:

  1. In all classes that you want to serialize or deserialize you should define << OPERATOR

    USTRUCT(BlueprintType)
    class SomeClass: public UObject {
    GENERATED_BODY()

    … // All you props, for example Prop1, Prop2, etc

    friend FArchive& operator<<(FArchive& Ar, SomeClass& objToSerialize) {
    Ar << objToSerialize.Prop1;
    Ar << objToSerialize.Prop2;

    return Ar;
    }
    };

  2. Saving data in file is simple as this

    void Save(SomeClass& objToSave) {

     FString filePath = FPaths::ProjectSavedDir() + "mydata.sav"; // file path you want
    
     FBufferArchive SaveData;
     SaveData << objToSave;
     FFileHelper::SaveArrayToFile(SaveData, *filePath);
    
     SaveData.FlushCache();
     SaveData.Empty();
    

    }

And some additional remarks:

  • you can easily serialize and deserialize TArray if T is serializable in the sense of 1)
  • serialize and deserialize in Unreal both are implemented with the same << OPERATOR. The thing is that some FArchive child classes save data and others - load. For example, FBufferArchive saves data from classes to stream (same as std::cout), while FMemoryReader can read data from stream to variables (same as std::cin)
  • To serialize and deserialize class B that has class A prop, work it out with class A and after that you can start with class B
  • UClass refs (TSubclassOf) can be serialized and deserialized by GetPathName() and StaticLoadClass(…) methods respectively
2 Likes

Sorry, but I forgot to tell that I figured it out an hour ago. I’ll post the answer shortly.

How to define the “Save”?
I know the blueprintNode SaveToSlot,the derived class of the SaveGameBP will as a .sav file on your hard drive,the path is /ProjectName/Saved/SaveGames/.
I know the C++ method,it can record the member variables of blueprint and then you can restore these member variables,its complete process is the following.

//it’s a general process,don’t panic…
struct Archive_TypeA : public FObjectAndNameAsStringProxyArchive
{
//it’s a kind of design,don’t panic,they call it C++ API Wrapper mode,
Archive_TypeA(FArchive& HaHa):FObjectAndNameAsStringProxyArchive(HaHa,true){

//ArIsSaveGame is not defined by me,it’s by source,why I can operate this variable?because Archive_TypeA inherits the FObjectAndNameAsStringProxyArchive.
//If you set this boolean as true,only those member variables whose boolean variable called SaveGame is checked will be considered for serialization.
ArIsSaveGame=true;

}
//complete the above,the following is simple.

//you need a derived class object ptr of UObject,that’s object you want to record,you can pass it in as a parameter.
//ptr is pointer,about pointer you can look this web Function Pointer in C++ - GeeksforGeeks
//NR is the abbreviation for Need To Be Recorded
UObject* Object_NTBR;

}

//The following is record data,you can encapsulate them as a function named “RecordData()”

//the data recorded in this,but what makes me feel curious is that the length of this array is always 0.
TArray Array_Uint8;
FMemoryWriter MW(Array_Uint8);
FArchive_TypeA Ar(MW);
Object_NTBR->Serialize(Ar);
//After serialization by MW Array_Uint8 has data,but its length is 0,I can not understand it.
//why I emphasize MW(MemoryWriter)?you can understand its impact by comparing MW(MemoryWriter) and MR(MemoryReader).

//The following is apply data to Blueprint,you can encapsulate them as a function named"ApplyData()"

//MR
FMemoryReader MR(Array_Uint8);
FArchive_TypeA Ar(MR);
//NTBA is the abbreviation for Need to be apply data,it is a parameter,it’s a pointer,it’s your Blueprint reference to self.
Object_NTBA->Serialize(Ar);

//how to test the above code?you can test them via UserWidget,press 1 key .
//1.write the above code in a derived class of USaveGame,because USaveGame can be as .sav file in hard drive(BlueprintNode is saveGameToSlot and loadGameFromSlot),its enduring premise is hard drive,as long as the hard drive is not destroyed,it always exist.
//2.Distinguish the enduringAbility of USaveGame and the recordAbility of Serialize().
//3.UPROPERTY() must be written before the member variable in USaveGameClass otherwise this variable will not be save to .sav file.
//4.you definitely need record multiple object,declare a TArray Array_OR in derived class of USaveGame,at the beginning,FObjectRecorder only need a memberVariable called ClassFName,however,if you want to record multiple objects of the same class,you need define extra FName to distinguish them,if you do not understand the meaning of Array_OR,I believe you will understand it.
//5.if you want achieve multiple archives,you can define 2 derived classes of USaveGame,the first class named SG_TypeA,it stores all slotNames(You can use membership policy,Think of SG_TypeA as a platinum membership registration form),the second class named SG_TypeB,it represent a archive,so we has
//6.I am not rich,@reanadore is my Twitter,you can access me and give me some money for food,thanks for watching,stay awesome,sign out.