Serialize script fields in "array" + more forgiving deserialization

This commit is contained in:
Simon Lübeß
2023-07-17 04:04:01 +02:00
parent 88b393157a
commit 66d66d3308
2 changed files with 97 additions and 37 deletions
+15 -13
View File
@@ -60,33 +60,35 @@ extension ScriptFieldType
case .Long: case .Long:
return typeof(int64); return typeof(int64);
case .Byte: case .Byte:
return typeof(uint8); return typeof(uint8);
case .UShort: case .UShort:
return typeof(uint16); return typeof(uint16);
case .UInt: case .UInt:
return typeof(uint32); return typeof(uint32);
case .ULong: case .ULong:
return typeof(uint64); return typeof(uint64);
case .Float: case .Float:
return typeof(float); return typeof(float);
case .float2: case .float2:
return typeof(float2); return typeof(float2);
case .float3: case .float3:
return typeof(float3); return typeof(float3);
case .float4: case .float4:
return typeof(float4); return typeof(float4);
case .Double: case .Double:
return typeof(double); return typeof(double);
case .Double2: case .Double2:
return typeof(double2); return typeof(double2);
case .Double3: case .Double3:
return typeof(double3); return typeof(double3);
case .Double4: case .Double4:
return typeof(double4); return typeof(double4);
case .Entity:
return typeof(UUID);
default: default:
return null; return null;
+82 -24
View File
@@ -194,16 +194,30 @@ class SceneSerializer
if (component.HasScript) if (component.HasScript)
{ {
let fields = ScriptEngine.GetScriptFieldMap(entity); let fields = ScriptEngine.GetScriptFieldMap(entity);
writer.Identifier("Fields");
for (var (fieldName, fieldInstance) in fields) using (writer.ArrayBlock())
{ {
switch (fieldInstance.Field.FieldType) for (var (fieldName, fieldInstance) in fields)
{ {
case .Entity, .Enum, .Class, .Struct: if (fieldInstance.Field.FieldType == .None)
// TODO: implement continue;
default:
writer.Identifier(fieldName);
Serialize.Value(writer, ValueView(fieldInstance.Field.FieldType.GetBeefType(), &fieldInstance.[Friend]_data), gBonEnv); switch (fieldInstance.Field.FieldType)
{
case .Enum, .Class, .Struct:
// TODO: implement
default:
writer.Identifier(fieldName);
String str = scope .();
fieldInstance.Field.FieldType.ToString(str);
writer.Type(str);
Serialize.Value(writer, ValueView(fieldInstance.Field.FieldType.GetBeefType(), &fieldInstance.[Friend]_data), gBonEnv);
}
} }
} }
} }
@@ -566,29 +580,73 @@ class SceneSerializer
var fields = ScriptEngine.GetScriptFieldMap(entity); var fields = ScriptEngine.GetScriptFieldMap(entity);
Try!(reader.EntryEnd()); Try!(reader.EntryEnd());
bool first = true; if (Try!(reader.Identifier()) == "Fields")
while (reader.ObjectHasMore())
{ {
if (first) Try!(reader.ArrayBlock());
first = false;
else bool dontRemoveComma = true;
Try!(reader.EntryEnd());
// TODO: We could think about doing the Try! a little smarter... // Remove whitespace before the check
// However we always might just fail to deserialize, so it doesn't really matter. while (reader..ConsumeEmpty().ArrayHasMore())
StringView fieldName = Try!(reader.Identifier());
if (fields.ContainsKey(fieldName))
{ {
var field = ref fields[fieldName]; if (dontRemoveComma)
dontRemoveComma = false;
else
{
if (reader.[Friend]Check(',', false))
reader.EntryEnd();
else
reader..FileEntrySkip(1).ConsumeEmpty();
}
// TODO: We could think about doing the Try! a little smarter...
// However we always might just fail to deserialize, so it doesn't really matter.
// It does matter... in case of an error we should try to skip to the next entry.
StringView fieldName = Try!(reader.Identifier());
void* data = &field.[Friend]_data; if (fields.ContainsKey(fieldName))
{
var field = ref fields[fieldName];
Try!(Deserialize.Value(reader, ValueView(field.Field.FieldType.GetBeefType(), data), gBonEnv)); Result<StringView> fieldTypeName = reader.Type();
if (fieldTypeName case .Err)
{
Log.EngineLogger.Error($"Failed to read field type for field \"{fieldName}\" in script \"{component.ScriptClass.FullName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1);
dontRemoveComma = true;
continue;
}
Result<ScriptFieldType> fieldType = Enum.Parse<ScriptFieldType>(fieldTypeName, true);
if ((fieldType case .Err) || (fieldType != field.Field.FieldType))
{
Log.EngineLogger.Error($"Unexpected field type (\"{fieldTypeName}\" instead of \"{field.Field.FieldType}\" for field: \"{fieldName}\" in script \"{component.ScriptClass.FullName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1);
dontRemoveComma = true;
continue;
}
void* data = &field.[Friend]_data;
if (Deserialize.Value(reader, ValueView(field.Field.FieldType.GetBeefType(), data), gBonEnv) case .Err)
{
Log.EngineLogger.Error($"Failed to deserialize data for field: \"{fieldName}\" in script \"{component.ScriptClass.FullName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1);
dontRemoveComma = true;
continue;
}
}
else
{
Log.EngineLogger.Error($"Script \"{component.ScriptClass.FullName}\" doesn't have a field with name \"{fieldName}\". (Entity {entity.UUID} (\"{entity.Name}\"))");
}
} }
Try!(reader.ArrayBlockEnd());
} }
} }