Add OnSerializing/OnSerialized/OnDeserializing/OnDeserialized callbacks to auto serialization code-gen

This commit is contained in:
Wojtek Figat
2026-01-09 10:24:38 +01:00
parent 14d1b7dd24
commit 4b9fa0dcf5
3 changed files with 45 additions and 0 deletions

View File

@@ -29,6 +29,15 @@ public:
/// </summary>
typedef JsonWriter SerializeStream;
/// <summary>
/// Serialization callback context container. Used by OnSerializing, OnSerialized, OnDeserializing, OnDeserialized methods.
/// </summary>
struct FLAXENGINE_API CallbackContext
{
// The deserialization modifier object.
ISerializeModifier* Modifier = nullptr;
};
public:
/// <summary>

View File

@@ -1879,6 +1879,25 @@ namespace Flax.Build.Bindings
return false;
}
private static void GenerateCppAutoSerializationCallback(BuildData buildData, StringBuilder contents, ApiTypeInfo typeInfo, string callback, string context)
{
// Generate invoking custom serialization callbacks (pre/post serialization/deserialization)
if (typeInfo is ClassStructInfo classStructInfo)
{
foreach (var functionInfo in classStructInfo.Functions)
{
if (functionInfo.Name != callback)
continue;
if (functionInfo.Parameters.Count != 1 && functionInfo.Parameters[0].Type.Type != "CallbackContext")
{
Log.Warning(GetBuildErrorLocation(typeInfo, $"Invalid serialization callback parameters in function '{typeInfo.Name}::{functionInfo.Name}'"));
continue;
}
contents.AppendLine($" {typeInfo.NativeName}::{functionInfo.Name}({context});");
}
}
}
private static void GenerateCppAutoSerialization(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, ApiTypeInfo typeInfo, string typeNameNative)
{
var classInfo = typeInfo as ClassInfo;
@@ -1892,9 +1911,14 @@ namespace Flax.Build.Bindings
CppAutoSerializeProperties.Clear();
CppIncludeFiles.Add("Engine/Serialization/Serialization.h");
// ISerializable::CallbackContext
var callbackContextSerialize = "{ nullptr }";
var callbackContextDeserialize = "{ modifier }";
contents.AppendLine();
contents.Append($"void {typeNameNative}::Serialize(SerializeStream& stream, const void* otherObj)").AppendLine();
contents.Append('{').AppendLine();
GenerateCppAutoSerializationCallback(buildData, contents, typeInfo, "OnSerializing", callbackContextSerialize);
if (baseType != null)
contents.Append($" {baseType.FullNameNative}::Serialize(stream, otherObj);").AppendLine();
contents.Append($" SERIALIZE_GET_OTHER_OBJ({typeNameNative});").AppendLine();
@@ -1953,11 +1977,13 @@ namespace Flax.Build.Bindings
}
}
GenerateCppAutoSerializationCallback(buildData, contents, typeInfo, "OnSerialized", callbackContextSerialize);
contents.Append('}').AppendLine();
contents.AppendLine();
contents.Append($"void {typeNameNative}::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)").AppendLine();
contents.Append('{').AppendLine();
GenerateCppAutoSerializationCallback(buildData, contents, typeInfo, "OnDeserializing", callbackContextDeserialize);
if (baseType != null)
contents.Append($" {baseType.FullNameNative}::Deserialize(stream, modifier);").AppendLine();
@@ -1979,6 +2005,7 @@ namespace Flax.Build.Bindings
contents.AppendLine(" }");
}
GenerateCppAutoSerializationCallback(buildData, contents, typeInfo, "OnDeserialized", callbackContextDeserialize);
contents.Append('}').AppendLine();
}

View File

@@ -62,6 +62,15 @@ namespace Flax.Build.Bindings
return $"{context.File.Name}({context.Tokenizer.CurrentLine}): {msg}";
}
private static string GetBuildErrorLocation(ApiTypeInfo typeInfo, string msg)
{
// Make it a link clickable in Visual Studio build output
var file = typeInfo.File;
if (file != null)
return $"{file.Name}(0): {msg}";
return msg;
}
private static string[] ParseComment(ref ParsingContext context)
{
if (context.StringCache == null)