https://www.mediafire.com/convkey/7d2b/fr75kbso2kkazru6g.jpg
Dear Community,
I have been hard at work making UE4 C++ Code tutorials!
I have added 28 pages of entirely code-focused tutorials, including both .h and .cpp,
to the UE4 Wiki Code Page!
**Tutorial Sample**
Here is most of a tutorial that is the kind of code and information I am posting on the UE4 Wiki Code Page!
**Custom Save System To Binary Files**
I've been planning to do this tutorial for months,
I will try to keep it as succinct as possible!
**Using what I explain in this tutorial you can write your own custom save systems wherein you**
```
- write out literally any game-related data you want
- read back in this data any time you want, from hard-disk
- compress (ZLIB) these files to minimize usage of the end-user's computer hard disk space
```
I've already been writing out and loading back in levels that are zipped binary data files for my in-game editor.
I am currently able to save literally any custom data I want, including dynamic arrays, for all my custom classes.
I've developed a streamlined method for doing all this by overloading a specific UE4 C++ operator, so yay thank you thank you Epic for C++ access!
Two Levels of Conversions
When you want to save custom variable data for your custom save system,
there are TWO major steps involved
Step 1 = variable format → binary array (serialized by Archive class of UE4)
Step 2 = Binary array → hard disk
These steps are then done in reverse to read back in data from hard disk.
**Binary Array = TArray<uint8>**
Binary data is represented in a very UE4 C++ friendly looking way as a dynamic array of uint8.
So any time you see TArray<uint8> in my code in this tutorial, that literally means "Binary Array" from UE4 C++ standpoint.
//Abbreviated to fit the new forum character limit
**Archive.h and ArchiveBase.h**
See Archive.h and ArchiveBase.h for all the info you need about getting from your varibles and custom class data to binary format (serialized data)
FileManager.h
All the functions you need to
- create directories
- delete directories
- create files
- delete files
- get a listing of all files in a given path
- get al isting of all folders in a given path
- get the age of a file
and more
are found in FileManager.h
You access these functions from anywhere using
if(GFileManager) GFileManager->TheFunction()
**BufferArchive**
The buffer archive is both a binary array (TArray<uint8>), and a MemoryWriter
**Archive.h**
```
/**
* Buffer archiver.
*/
class FBufferArchive : public FMemoryWriter, public TArray<uint8>
{
```
Because of this multiple-inheritance, the BufferArchive is my preferred way to write data to binary file.
As my code will show, because the GFileManager wants to receive a TArray<uint8>, not a MemoryArchive.
Review my Steps 1 and 2 to see why this is such an awesome class. :)
Thanks UE4 Devs!
FMemoryReader
To read Data back from a binary array, that is retrieved by the FileManager, you need a MemoryReader
Archive.h
/**
* Archive for reading arbitrary data from the specified memory location
*/
class FMemoryReader : public FMemoryArchive
{
public:
The << Operator
The BufferArchive/Binary Array needs to retrieve your game's variable data, how do you tell it what you want stored as binary?
The << operator!
**Variable -> Binary**
Here's how you would put an FVector into a BufferArchive to then be saved to hard disk.
//in player controller class
```
FBufferArchive ToBinary;
ToBinary << GetPawn()->GetActorLocation(); //save player location to hard disk
//save ToBinary to hard disk using File Manager,
//see complete code samples below
```
**Binary -> Variable**
Here's how you would retrieve an FVector from a TArray<uint8> as retrieved by GFileManager.
/
```
/TheBinaryArray was already obtained from FileManager,
//see code below for full examples
//need to supply a variable to be filled with the data
FVector ToBeFilledWithData;
FMemoryReader Ar = FMemoryReader(TheBinaryArray, true); //true, free data after done
Ar.Seek(0); //make sure we at the beginning
Ar << ToBeFilledWithData;
```
The Hardest Concept of UE4 C++ Custom Save System
Please notice something in my code above!!!
Compare these two lines
ToBinary << GetPawn()->GetActorLocation();
Ar << ToBeFilledWithData;
The hardest concept for me about the UE4 archive system was the fact that the << operator could mean
- getting data out of the archive and putting it into the variable
or
- putting data from the variable into the archived binary format
depending on the context!
So that’s why I recommend you name your BufferArchive something like ToBinary,
and your MemoryReader something totally different,
you can only discern the difference between writing to binary and reading from binary
based on the context as you show it in your code, as the << operator will tell you nothing from a simple glance.
**Writing Your Function to Be Two-Way**
The critical advantage of this system though is that you can write a single function that works both ways.
So you can write a single function that loads data from file, or saves to file.
But why would you want this?
Because:
**===================================================
The order of how you write out data to binary file must be the EXACT SAME ORDER that you read it back in!
===================================================**
The computer does not have any way of knowing, nor does UE4, what the correct order of variable data should be.
You are responsible for telling the computer and UE4 to read data back in in the same order it was written out to file.
Thus, having a single function that both reads and writes, using the multi-purpose << operator, is the safest thing you can do to ensure consistency of writing/reading binary data.
**==========================
Two-Way Save System Function
==========================**
```
**.h**
//FArchive is shared base class for FBufferArchive and FMemoryReader
void SaveLoadData(FArchive& Ar, int32& SaveDataInt32, FVector& SaveDataVector, TArray<FRotator>& SaveDataRotatorArray);
**.cpp**
//I am using controller class for convenience, use any class you want
//SaveLoadData
void YourControllerClass::SaveLoadData(FArchive& Ar,
int32& SaveDataInt32,
FVector& SaveDataVector,
TArray<FRotator>& SaveDataRotatorArray
)
{
Ar << SaveDataInt32;
Ar << SaveDataVector;
Ar << SaveDataRotatorArray;
}
```
**Saving**
Make a BufferArchive and pass it in, it is a Binary Array and also an FArchive
```
FBufferArchive ToBinary;
SaveLoadData(ToBinary,NumGemsCollected,PlayerLocation,ArrayOfRotationsOfTheStars);
//save the binary array / FBufferArchive to hard disk, see below
```
**Loading**
//TheBinaryArray already retrieved from file, see full code sapmle
```
FMemoryReader FromBinary = FMemoryReader(TheBinaryArray, true); //true, free data after done
FromBinary.Seek(0);
SaveLoadData(FromBinary,NumGemsCollected,PlayerLocation,ArrayOfRotationsOfTheStars);
```
**Summary**
Use this setup to avoid crashes due to reading data not in same order that you wrote it to disk!
this two way functionality of UE4 << operator saves the day!
Thanks Epic Devs!
Saving Compressed Binary Files
bool ControllerClass::SaveGameDataToFileCompressed(const FString& FullFilePath,
int32& SaveDataInt32,
FVector& SaveDataVector,
TArray<FRotator>& SaveDataRotatorArray
){
FBufferArchive ToBinary;
SaveLoadData(ToBinary,NumGemsCollected,PlayerLocation,ArrayOfRotationsOfTheStars);
//Pre Compressed Size
ClientMessage("~ PreCompressed Size ~");
ClientMessage(FString::FromInt(ToBinary.Num()));
//~~~
//~~~ Compress File ~~~
//tmp compressed data array
TArray<uint8> CompressedData;
FArchiveSaveCompressedProxy Compressor =
FArchiveSaveCompressedProxy(CompressedData, ECompressionFlags::COMPRESS_ZLIB);
//Send entire binary array/archive to compressor
Compressor << ToBinary;
//send archive serialized data to binary array
Compressor.Flush();
//~~~
//Compressed Size
ClientMessage("~ Compressed Size ~");
ClientMessage(FString::FromInt(CompressedData.Num()));
if (!GFileManager) return false;
//vibes to file, return successful or not
if (FFileHelper::SaveArrayToFile(CompressedData, * FullFilePath))
{
//~~~ Free Binary Arrays ~~~
Compressor.FlushCache();
CompressedData.Empty();
ToBinary.FlushCache();
ToBinary.Empty();
//~~~ Close Buffer ~~~
ToBinary.Close();
ClientMessage("File Save Success!");
return true;
//~~~~~~~~~~~~~~~
}
else
{
//~~~ Free Binary Arrays ~~~
Compressor.FlushCache();
CompressedData.Empty();
ToBinary.FlushCache();
ToBinary.Empty();
//~~~ Close Buffer ~~~
ToBinary.Close();
ClientMessage("File Could Not Be Saved!");
return false;
//~~~~~~~~~~~~~~~
}
}
**Loading Compressed Binary Files**
See [UE4 Wiki Code Page](https://wiki.unrealengine.com/Category:Code)
**Enjoy!**
Have fun making your very own custom save game system!
♥
Rama