Введение
Допустим, вы создали свою USTRUCT в C++ и хотите её сериализовать.
USTRUCT(BlueprintType) struct FComplexStruct { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite) FNonSerializableStruct FirstStruct; UPROPERTY(EditAnywhere, BlueprintReadWrite) FSerializableStruct SecondStruct; };
Обычно, достаточно просто пометить нужные поля как SaveGame
.
USTRUCT(BlueprintType) struct FComplexStruct { GENERATED_BODY() // Не поддерживает сериализацию UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame) FNonSerializableStruct FirstStruct; // Поддерживает сериализацию UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame) FSerializableStruct SecondStruct; };
Но вот проблема, для этого они сами должны поддерживать сериализацию. К сожалению, одна из наших переменных ее не поддерживает. В моем случае, это структура FNonSerializableStruct
. Из-за этого сериализуется только вторая структура, хоть мы и пометили SaveGame
обе.
Решение
И как же тогда быть? В таком случае, нам придется вручную сериализовать нашу структуру. Благо, это довольно просто сделать. Для этого нам нужно за пределами структуры, глобально, для файла, добавить следующее:
inline FArchive& operator<<(FArchive& Ar, FComplexStruct& Save) { Save.Serialize(Ar); return Ar; } template <> struct TStructOpsTypeTraits<FComplexStruct> : public TStructOpsTypeTraitsBase2<FComplexStruct> { enum { WithSerializer = true }; };
Тут, в шаблонной структуре, мы говорим движку, что мы хотим вручную сериализовать нашу структуру.
Перегрузка оператора <<
добавлена чисто для удобства, дабы не вызывать всегда метод Serialize
руками, если мы захотим использовать нашу структуру как поле другой структуры/класса.
Окей, что делать дальше? Мы ведь так и не написали нашу сериализацию.
Я уже упомянул выше метод Serialize
. Его нам и надо добавить в нашу структуру. Движок его вызовет сам, когда надо. Сделает он это благодаря коду, который мы написали выше.
bool Serialize(FArchive& Ar) { // Сериализуем частями, т.к. поддержки нет Ar << FirstStruct.Type; Ar << FirstStruct.Class; Ar << FirstStruct.Object; // Сериализуем целиком, т.к. есть поддержка Ar << SecondStruct; return true; }
Полный код
USTRUCT(BlueprintType) struct FComplexStruct { GENERATED_BODY() // Не поддерживает сериализацию UPROPERTY(EditAnywhere, BlueprintReadWrite) FNonSerializableStruct FirstStruct; // Поддерживает сериализацию UPROPERTY(EditAnywhere, BlueprintReadWrite) FSerializableStruct SecondStruct; bool Serialize(FArchive& Ar) { // Сериализуем частями, т.к. поддержки нет Ar << FirstStruct.Type; Ar << FirstStruct.Class; Ar << FirstStruct.Object; // Сериализуем целиком, т.к. есть поддержка Ar << SecondStruct; return true; } }; inline FArchive& operator<<(FArchive& Ar, FComplexStruct& Save) { Save.Serialize(Ar); return Ar; } template <> struct TStructOpsTypeTraits<FComplexStruct> : public TStructOpsTypeTraitsBase2<FComplexStruct> { enum { WithSerializer = true }; };
Улучшение
Можно заметить, что код добавления поддержки сериализации довольно шаблонный. Что это означает? Мы можем сделать макрос, дабы сильно облегчить добавление поддержки для других структур!
#define MAKE_SERIALIZABLE_STRUCT(Name) \ inline FArchive& operator<<(FArchive& Ar, Name& Save) \ { \ Save.Serialize(Ar); \ return Ar; \ } \ template<> \ struct TStructOpsTypeTraits<Name> : public TStructOpsTypeTraitsBase2<Name> \ { \ enum \ { \ WithSerializer = true, \ }; \ };
Теперь мы можем просто закинуть наш макрос в какой-нибудь хедер и довольно лаконично добавить поддержку сериализации для любой нашей структуры.
Финальный код
USTRUCT(BlueprintType) struct FComplexStruct { GENERATED_BODY() // Не поддерживает сериализацию UPROPERTY(EditAnywhere, BlueprintReadWrite) FNonSerializableStruct FirstStruct; // Поддерживает сериализацию UPROPERTY(EditAnywhere, BlueprintReadWrite) FSerializableStruct SecondStruct; bool Serialize(FArchive& Ar) { // Сериализуем частями, т.к. поддержки нет Ar << FirstStruct.Type; Ar << FirstStruct.Class; Ar << FirstStruct.Object; // Сериализуем целиком, т.к. есть поддержка Ar << SecondStruct; return true; } }; MAKE_SERIALIZABLE_STRUCT(FComplexStruct);
Итог
Теперь вы можете без труда добавлять поддержку сериализации для собственных структур в Unreal Engine, даже если их поля изначально не поддерживают эту функцию.
ссылка на оригинал статьи https://habr.com/ru/articles/865170/
Добавить комментарий