Serialization (Memory Archive)
언리얼에서 제공하는 기본적인 메모리 직렬화 객체 FMemoryArchive를 활용한 예제이다.
언리얼에서는 메모리 읽기, 쓰기 기능을 지원하기 위해 FMemoryArchive를 상속하여 FMemoryReader, FMemoryWriter 형태로 제공한다.
#include "Serialization/MemoryWriter.h"
#include "Serialization/MemoryReader.h"
void SerializationExamples::BaseExample()
{
UE_LOG(LogTemp, Log, TEXT("BaseExample Begin"));
// write data to memory
TArray<uint8> BufferArray;
FMemoryWriter Writer(BufferArray);
{
uint32 A = 15;
uint32 B = 75;
FString C = TEXT("blabla");
Writer << A;
Writer << B;
Writer << C;
UE_LOG(LogTemp, Log, TEXT("BufferArray Num : %d"), BufferArray.Num());
}
// read data from memory
FMemoryReader Reader(BufferArray);
{
uint32 A;
uint32 B;
FString C;
Reader << A;
Reader << B;
Reader << C;
UE_LOG(LogTemp, Log, TEXT("A : %u B : %u C : %s"), A, B, *C);
}
UE_LOG(LogTemp, Log, TEXT("BaseExample End"));
}
Struct Serialization
구조체도 직렬화 로직을 정의해 준다면 같은 형태로 직렬화할 수 있다.
struct SerializationExampleData
{
uint32 A;
uint32 B;
FString C;
// for read / write serialization for this struct
friend FArchive& operator<<(FArchive& Ar, SerializationExampleData& Data)
{
Ar << Data.A;
Ar << Data.B;
Ar << Data.C;
return Ar;
}
};
void SerializationExamples::StructExample()
{
UE_LOG(LogTemp, Log, TEXT("StructSerializeExample Begin"));
TArray<uint8> BufferArray;
FMemoryWriter Writer(BufferArray);
{
SerializationExampleData Data;
Data.A = 99;
Data.B = 13;
Data.C = TEXT("blabla");
Writer << Data;
UE_LOG(LogTemp, Log, TEXT("BufferArray Num : %d"), BufferArray.Num());
}
FMemoryReader Reader(BufferArray);
{
SerializationExampleData Data;
Reader << Data;
UE_LOG(LogTemp, Log, TEXT("Data A : %u Data B : %u Data C : %s"), Data.A, Data.B, *Data.C);
}
{
// need to seek to use again
Reader.Seek(0);
SerializationExampleData Data;
Reader << Data;
UE_LOG(LogTemp, Log, TEXT("Data A : %u Data B : %u Data C : %s"), Data.A, Data.B, *Data.C);
}
{
// this will not work properly
SerializationExampleData Data;
Reader << Data;
UE_LOG(LogTemp, Log, TEXT("Data A : %u Data B : %u Data C : %s (Error Case)"), Data.A, Data.B, *Data.C);
}
{
// once reader offset overflowed, it doesn't work properly even if seek offset
Reader.Seek(0);
SerializationExampleData Data;
Reader << Data;
UE_LOG(LogTemp, Log, TEXT("Data A : %u Data B : %u Data C : %s (Error Case)"), Data.A, Data.B, *Data.C);
}
// safe example - just create archive object in brace
{
FMemoryReader MemReader(BufferArray);
SerializationExampleData Data;
MemReader << Data;
UE_LOG(LogTemp, Log, TEXT("Data A : %u Data B : %u Data C : %s"), Data.A, Data.B, *Data.C);
}
UE_LOG(LogTemp, Log, TEXT("StructSerializeExample End"));
}
Object Serialization
객체 직렬화 예제이다.
UENUM(BlueprintType)
enum class EType : uint8
{
Type1,
Type2
};
UCLASS()
class UNREALEXAMPLES_API USerializationExampleObject : public UObject
{
GENERATED_BODY()
public:
USerializationExampleObject() {}
UPROPERTY(EditAnywhere, Category = "Voice Characteristics")
EType Language;
UPROPERTY(EditAnywhere, Category = "Conversion")
FString SaveAssetTo;
// 참조 형태의 변수는 Serialize 후 파일 Read/Write 과정에 문제가 생길 수 있다.
// 따로 경로만 저장하는 형태로 개발하거나,
// Config에 저장하는 형태로 개발하는것이 좋다.
//UPROPERTY(EditAnywhere, Category = "Conversion")
// USkeleton* TargetSkeleton;
UPROPERTY(EditAnywhere, Category = "Conversion")
int32 ImportAudioNumber;
UPROPERTY(EditAnywhere, Category = "Conversion")
bool bInsertPlaySoundNotify;
UPROPERTY(EditAnywhere, Category = "FilesToDump")
bool bPhoneme;
UPROPERTY(EditAnywhere, Category = "FilesToDump")
bool bAnimClip;
UPROPERTY(EditAnywhere, Category = "FilesToDump")
bool bConversionLog;
};
void SerializationExamples::ObjectExample()
{
UE_LOG(LogTemp, Log, TEXT("ObjectExample Begin"));
TArray<uint8> BufferArray;
// write
{
FMemoryWriter Writer(BufferArray);
USerializationExampleObject* Obj = NewObject<USerializationExampleObject>();
Obj->Language = EType::Type2;
Obj->SaveAssetTo = TEXT("Maybe/Some/Directory/Path/Here");
Obj->ImportAudioNumber = 33;
Obj->bInsertPlaySoundNotify = true;
Obj->bPhoneme = false;
Obj->bAnimClip = true;
Obj->bConversionLog = false;
Obj->Serialize(Writer);
UE_LOG(LogTemp, Log, TEXT("BufferArray Num : %d"), BufferArray.Num());
}
// read
{
FMemoryReader Reader(BufferArray);
USerializationExampleObject* Obj = NewObject<USerializationExampleObject>();
Obj->Serialize(Reader);
UE_LOG(LogTemp, Log, TEXT("Readed Data : %d %s %d %d %d %d %d"),
Obj->Language,
*Obj->SaveAssetTo,
Obj->ImportAudioNumber,
Obj->bInsertPlaySoundNotify,
Obj->bPhoneme,
Obj->bAnimClip,
Obj->bConversionLog);
}
UE_LOG(LogTemp, Log, TEXT("ObjectExample End"));
}
File Serialization
파일 직렬화 예제이다.
oid SerializationExamples::FileExample()
{
UE_LOG(LogTemp, Log, TEXT("FileExample Begin"));
FString FullPath = FString::Printf(TEXT("%s%s"), *FPaths::ProjectSavedDir(), TEXT("save.txt"));
// write
FArchive* FileWriter = IFileManager::Get().CreateFileWriter(*FullPath);
if (FileWriter)
{
FString T1 = FString(TEXT("AAA"));
FString T2 = FString(TEXT("BBB"));
*FileWriter << T1;
*FileWriter << T2;
FileWriter->Close();
delete FileWriter;
FileWriter = NULL;
}
// read (can be used with TSharedPtr, which deletes memory by-self)
TSharedPtr<FArchive> FileReader = MakeShareable(IFileManager::Get().CreateFileReader(*FullPath));
if (FileReader.IsValid())
{
FString Temp1;
FString Temp2;
*FileReader.Get() << Temp1;
*FileReader.Get() << Temp2;
FileReader->Close();
UE_LOG(LogTemp, Log, TEXT("%s %s"), *Temp1, *Temp2);
}
UE_LOG(LogTemp, Log, TEXT("FileExample End"));
}
메모리 데이터를 파일에 직렬화할 수도 있다.
void SerializationExamples::MemoryAndFileExample()
{
UE_LOG(LogTemp, Log, TEXT("MemoryAndFileExample Begin"));
FString FullPath = FString::Printf(TEXT("%s%s"), *FPaths::ProjectSavedDir(), TEXT("save.txt"));
// write (data -> memory -> file)
TSharedPtr<FArchive> FileWriter = MakeShareable(IFileManager::Get().CreateFileWriter(*FullPath));
if (FileWriter.IsValid())
{
TArray<uint8> Buffer;
FMemoryWriter MemoryWriter(Buffer);
SerializationExampleData Data;
Data.A = 99;
Data.B = 13;
Data.C = TEXT("blabla");
MemoryWriter << Data;
*FileWriter << Buffer;
FileWriter->Close();
}
// read (file -> memory -> data)
TSharedPtr<FArchive> FileReader = MakeShareable(IFileManager::Get().CreateFileReader(*FullPath));
if (FileReader.IsValid())
{
TArray<uint8> Buffer;
*FileReader << Buffer;
FMemoryReader MemoryReader(Buffer);
SerializationExampleData Data;
MemoryReader << Data;
FileReader->Close();
UE_LOG(LogTemp, Log, TEXT("Data A : %u Data B : %u Data C : %s"), Data.A, Data.B, *Data.C);
}
UE_LOG(LogTemp, Log, TEXT("MemoryAndFileExample End"));
}
Github
'게임 엔진 > Unreal' 카테고리의 다른 글
[Unreal] [Editor] Slate를 이용한 커스텀 에디터 List View 제작 (0) | 2020.06.29 |
---|---|
[Unreal] [Editor] 프로퍼티 에디터 제작 방법 (0) | 2020.06.26 |
[Unreal] [Editor] Slate를 이용한 에셋 경로 설정 다이얼로그 제작 (0) | 2020.06.24 |
[Unreal] [Editor] [Example] Slate 예제 1 (0) | 2020.06.22 |
[Unreal] [Editor] [Example] Slate 예제 2 (0) | 2020.06.22 |