Merge remote-tracking branch 'origin/master' into 1.13
# Conflicts: # Flax.flaxproj # Source/Engine/Level/Actors/StaticModel.cpp # Source/Engine/Level/Prefabs/Prefab.cpp # Source/Engine/Tools/ModelTool/ModelTool.cpp
This commit is contained in:
+13
-5
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace FlaxEngine.Json.JsonCustomSerializers
|
||||
@@ -44,6 +45,13 @@ namespace FlaxEngine.Json.JsonCustomSerializers
|
||||
((JsonObjectContract)contract).ItemReferenceLoopHandling = ReferenceLoopHandling.Serialize;
|
||||
}
|
||||
|
||||
// Check if use enum serialization as string
|
||||
var type = Nullable.GetUnderlyingType(objectType) ?? objectType;
|
||||
if (type.IsEnum && type.GetCustomAttribute<EnumStringAttribute>() != null)
|
||||
{
|
||||
contract.Converter = new StringEnumConverter();
|
||||
}
|
||||
|
||||
return contract;
|
||||
}
|
||||
|
||||
@@ -53,19 +61,19 @@ namespace FlaxEngine.Json.JsonCustomSerializers
|
||||
var contract = base.CreateDictionaryContract(objectType);
|
||||
|
||||
// Override contract to save enums keys as integer
|
||||
if (contract.DictionaryKeyType?.IsEnum ?? false)
|
||||
var keyType = contract.DictionaryKeyType;
|
||||
if ((keyType?.IsEnum ?? false) && keyType.GetCustomAttribute<EnumStringAttribute>() == null)
|
||||
{
|
||||
var enumType = contract.DictionaryKeyType;
|
||||
contract.DictionaryKeyResolver = name =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var e = Enum.Parse(enumType, name);
|
||||
var e = Enum.Parse(keyType, name);
|
||||
name = Convert.ToInt32(e).ToString();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Ignore errors
|
||||
Debug.Logger.LogHandler.LogWrite(LogType.Warning, $"Failed to parse enum '{name}' as {keyType.Name}: {ex.Message}");
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
@@ -49,6 +49,54 @@ void ISerializable::DeserializeIfExists(DeserializeStream& stream, const char* m
|
||||
var = defaultValue;\
|
||||
}
|
||||
|
||||
void Serialization::SerializeEnum(ISerializable::SerializeStream& stream, uint32 v, ScriptingTypeHandle typeHandle)
|
||||
{
|
||||
if (typeHandle)
|
||||
{
|
||||
// Check if serialize enum as string
|
||||
const ScriptingType& type = typeHandle.GetType();
|
||||
if (type.Type == ScriptingTypes::Enum && type.Enum.StringSerialization)
|
||||
{
|
||||
const auto items = type.Enum.Items;
|
||||
for (int32 i = 0; items[i].Name; i++)
|
||||
{
|
||||
if (items[i].Value == v)
|
||||
{
|
||||
stream.String(items[i].Name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.Uint(v);
|
||||
}
|
||||
|
||||
int32 Serialization::DeserializeEnum(ISerializable::DeserializeStream& stream, ScriptingTypeHandle typeHandle)
|
||||
{
|
||||
if (stream.IsString() && typeHandle)
|
||||
{
|
||||
// Deserialize enum from string
|
||||
const ScriptingType& type = typeHandle.GetType();
|
||||
if (type.Type == ScriptingTypes::Enum)
|
||||
{
|
||||
const auto str = stream.GetStringAnsiView();
|
||||
const auto items = type.Enum.Items;
|
||||
for (int32 i = 0; items[i].Name; i++)
|
||||
{
|
||||
if (str == items[i].Name)
|
||||
{
|
||||
return (int32)items[i].Value;
|
||||
}
|
||||
}
|
||||
int32 result;
|
||||
if (!StringUtils::Parse(stream.GetString(), &result))
|
||||
return result;
|
||||
LOG(Warning, "Failed to parse enum '{}' as {}", str.ToString(), type.Fullname.ToString());
|
||||
}
|
||||
}
|
||||
return DeserializeInt(stream);
|
||||
}
|
||||
|
||||
bool Serialization::ShouldSerialize(const VariantType& v, const void* otherObj)
|
||||
{
|
||||
return !otherObj || v != *(VariantType*)otherObj;
|
||||
@@ -129,7 +177,6 @@ void Serialization::Serialize(ISerializable::SerializeStream& stream, const Vari
|
||||
stream.Int64(v.AsInt64);
|
||||
break;
|
||||
case VariantType::Uint64:
|
||||
case VariantType::Enum:
|
||||
stream.Uint64(v.AsUint64);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
@@ -222,6 +269,9 @@ void Serialization::Serialize(ISerializable::SerializeStream& stream, const Vari
|
||||
else
|
||||
stream.String("", 0);
|
||||
break;
|
||||
case VariantType::Enum:
|
||||
SerializeEnum(stream, (int32)v.AsUint64, v.Type.GetScriptingType());
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
case VariantType::Structure:
|
||||
{
|
||||
@@ -276,7 +326,6 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
|
||||
v.AsInt64 = value.GetInt64();
|
||||
break;
|
||||
case VariantType::Uint64:
|
||||
case VariantType::Enum:
|
||||
v.AsUint64 = value.GetUint64();
|
||||
break;
|
||||
case VariantType::Float:
|
||||
@@ -371,6 +420,9 @@ void Serialization::Deserialize(ISerializable::DeserializeStream& stream, Varian
|
||||
CHECK(value.IsString());
|
||||
v.SetTypename(value.GetStringAnsiView());
|
||||
break;
|
||||
case VariantType::Enum:
|
||||
v.AsInt64 = DeserializeEnum(value, v.Type.GetScriptingType());
|
||||
break;
|
||||
case VariantType::ManagedObject:
|
||||
case VariantType::Structure:
|
||||
{
|
||||
|
||||
@@ -38,12 +38,16 @@ namespace Serialization
|
||||
int32 result = 0;
|
||||
if (stream.IsInt())
|
||||
result = stream.GetInt();
|
||||
else if (stream.IsInt64())
|
||||
result = (int32)stream.GetInt64();
|
||||
else if (stream.IsFloat())
|
||||
result = (int32)stream.GetFloat();
|
||||
else if (stream.IsString())
|
||||
StringUtils::Parse(stream.GetString(), &result);
|
||||
return result;
|
||||
}
|
||||
FLAXENGINE_API void SerializeEnum(ISerializable::SerializeStream& stream, uint32 v, ScriptingTypeHandle typeHandle);
|
||||
FLAXENGINE_API int32 DeserializeEnum(ISerializable::DeserializeStream& stream, ScriptingTypeHandle typeHandle);
|
||||
|
||||
// In-build types
|
||||
|
||||
@@ -226,12 +230,12 @@ namespace Serialization
|
||||
template<typename T>
|
||||
inline typename TEnableIf<TIsEnum<T>::Value>::Type Serialize(ISerializable::SerializeStream& stream, const T& v, const void* otherObj)
|
||||
{
|
||||
stream.Uint((uint32)v);
|
||||
SerializeEnum(stream, (uint32)v, StaticType<T>());
|
||||
}
|
||||
template<typename T>
|
||||
inline typename TEnableIf<TIsEnum<T>::Value>::Type Deserialize(ISerializable::DeserializeStream& stream, T& v, ISerializeModifier* modifier)
|
||||
{
|
||||
v = (T)DeserializeInt(stream);
|
||||
v = (T)DeserializeEnum(stream, StaticType<T>());
|
||||
}
|
||||
|
||||
// Common types
|
||||
|
||||
@@ -288,12 +288,15 @@ void ReadStream::Read(Variant& data)
|
||||
break;
|
||||
}
|
||||
case VariantType::Float2:
|
||||
case VariantType::Int2:
|
||||
ReadBytes(&data.AsData, sizeof(Float2));
|
||||
break;
|
||||
case VariantType::Float3:
|
||||
case VariantType::Int3:
|
||||
ReadBytes(&data.AsData, sizeof(Float3));
|
||||
break;
|
||||
case VariantType::Float4:
|
||||
case VariantType::Int4:
|
||||
ReadBytes(&data.AsData, sizeof(Float4));
|
||||
break;
|
||||
case VariantType::Double2:
|
||||
@@ -687,12 +690,15 @@ void WriteStream::Write(const Variant& data)
|
||||
Write(id);
|
||||
break;
|
||||
case VariantType::Float2:
|
||||
case VariantType::Int2:
|
||||
WriteBytes(data.AsData, sizeof(Float2));
|
||||
break;
|
||||
case VariantType::Float3:
|
||||
case VariantType::Int3:
|
||||
WriteBytes(data.AsData, sizeof(Float3));
|
||||
break;
|
||||
case VariantType::Float4:
|
||||
case VariantType::Int4:
|
||||
WriteBytes(data.AsData, sizeof(Float4));
|
||||
break;
|
||||
case VariantType::Double2:
|
||||
|
||||
Reference in New Issue
Block a user