mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
Handle generic PPtr fields in MonoBehaviour deserialization
* Resolves #1226
This commit is contained in:
parent
09ed03b735
commit
9c079d0a95
@ -0,0 +1,209 @@
|
||||
namespace AssetRipper.SerializationLogic.Tests;
|
||||
|
||||
public class CyclicalReferenceTests
|
||||
{
|
||||
[Serializable]
|
||||
private class SelfReferencingClass
|
||||
{
|
||||
public SelfReferencingClass? selfReference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D1()
|
||||
{
|
||||
SerializableType serializableType = SerializableTypes.Create<SelfReferencingClass>();
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(0)); // Infinite recursion disqualifies a field from serialization
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D2
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D2? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D2
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D2? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D2()
|
||||
{
|
||||
List<SerializableType> serializableType = SerializableTypes.CreateMultiple<CyclicalReferenceClass_C1_D2>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D3? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3()
|
||||
{
|
||||
List<SerializableType> serializableType = SerializableTypes.CreateMultiple<CyclicalReferenceClass_C1_D3>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D4? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D4? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C4_D4? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C4_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D4? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D4()
|
||||
{
|
||||
List<SerializableType> serializableType = SerializableTypes.CreateMultiple<CyclicalReferenceClass_C1_D4>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3_V1
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3_V1? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3_V1
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D3_V1? reference1;
|
||||
public CyclicalReferenceClass_C3_D3_V1? reference2;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3_V1
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V1? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3_V1()
|
||||
{
|
||||
// Variant 1: Two references to the same class
|
||||
List<SerializableType> serializableType = SerializableTypes.CreateMultiple<CyclicalReferenceClass_C1_D3_V1>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3_V2
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3_V2? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3_V2
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D3_V2? reference1;
|
||||
public CyclicalReferenceClass_C1_D3_V2? reference2;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3_V2
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V2? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3_V2()
|
||||
{
|
||||
// Variant 2: Reference to child class, then reference to parent class
|
||||
List<SerializableType> serializableType = SerializableTypes.CreateMultiple<CyclicalReferenceClass_C1_D3_V2>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3_V3
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3_V3? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3_V3
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V3? reference1;
|
||||
public CyclicalReferenceClass_C3_D3_V3? reference2;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3_V3
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V3? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3_V3()
|
||||
{
|
||||
// Variant 3: Reference to parent class, then reference to child class
|
||||
List<SerializableType> serializableType = SerializableTypes.CreateMultiple<CyclicalReferenceClass_C1_D3_V3>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
using AssetRipper.Primitives;
|
||||
|
||||
namespace AssetRipper.SerializationLogic.Tests;
|
||||
|
||||
public class FieldSerializationTests
|
||||
@ -15,7 +13,7 @@ public class FieldSerializationTests
|
||||
[Test]
|
||||
public void PrivateFieldsAreCorrectlyDiscriminated()
|
||||
{
|
||||
SerializableType serializableType = CreateSerializableType<CustomMonoBehaviourWithPrivateFields>();
|
||||
SerializableType serializableType = SerializableTypes.Create<CustomMonoBehaviourWithPrivateFields>();
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(1));
|
||||
SerializableType.Field field = serializableType.Fields[0];
|
||||
Assert.That(field.Name, Is.EqualTo("field1"));
|
||||
@ -32,7 +30,7 @@ public class FieldSerializationTests
|
||||
[Test]
|
||||
public void PublicFieldsAreCorrectlyDiscriminated()
|
||||
{
|
||||
SerializableType serializableType = CreateSerializableType<CustomMonoBehaviourWithPublicFields>();
|
||||
SerializableType serializableType = SerializableTypes.Create<CustomMonoBehaviourWithPublicFields>();
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(1));
|
||||
SerializableType.Field field = serializableType.Fields[0];
|
||||
Assert.That(field.Name, Is.EqualTo(nameof(CustomMonoBehaviourWithPublicFields.field2)));
|
||||
@ -46,7 +44,7 @@ public class FieldSerializationTests
|
||||
[Test]
|
||||
public void ResolutionForUnityTypesWorksAsExpected()
|
||||
{
|
||||
SerializableType serializableType = CreateSerializableType<CustomMonoBehaviourWithListField>();
|
||||
SerializableType serializableType = SerializableTypes.Create<CustomMonoBehaviourWithListField>();
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(1));
|
||||
SerializableType.Field field = serializableType.Fields[0];
|
||||
using (Assert.EnterMultipleScope())
|
||||
@ -71,7 +69,7 @@ public class FieldSerializationTests
|
||||
[Test]
|
||||
public void DeserializationSupportsGenericTypes()
|
||||
{
|
||||
SerializableType serializableType = CreateSerializableType<CustomMonoBehaviourWithGenericField>();
|
||||
SerializableType serializableType = SerializableTypes.Create<CustomMonoBehaviourWithGenericField>();
|
||||
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(1));
|
||||
SerializableType.Field field = serializableType.Fields[0];
|
||||
@ -91,248 +89,47 @@ public class FieldSerializationTests
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class SelfReferencingClass
|
||||
private class CustomMonoBehaviourWithObjectField : UnityEngine.MonoBehaviour
|
||||
{
|
||||
public SelfReferencingClass? selfReference;
|
||||
public UnityEngine.Object? pptr;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D1()
|
||||
private class CustomMonoBehaviourWithMonoBehaviourField : UnityEngine.MonoBehaviour
|
||||
{
|
||||
SerializableType serializableType = CreateSerializableType<SelfReferencingClass>();
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(0)); // Infinite recursion disqualifies a field from serialization
|
||||
public UnityEngine.Object? pptr;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D2
|
||||
private abstract class GenericAbstractMonoBehaviour<T> : UnityEngine.MonoBehaviour
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D2? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D2
|
||||
private class NonGenericDerivedMonoBehaviour : GenericAbstractMonoBehaviour<int>
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D2? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D2()
|
||||
private class CustomMonoBehaviourWithNonGenericDerivedMonoBehaviourField : UnityEngine.MonoBehaviour
|
||||
{
|
||||
List<SerializableType> serializableType = CreateSerializableTypes<CyclicalReferenceClass_C1_D2>();
|
||||
public NonGenericDerivedMonoBehaviour? pptr;
|
||||
}
|
||||
|
||||
private class CustomMonoBehaviourWithGenericAbstractMonoBehaviourField : UnityEngine.MonoBehaviour
|
||||
{
|
||||
public GenericAbstractMonoBehaviour<int>? pptr;
|
||||
}
|
||||
|
||||
[TestCase(typeof(CustomMonoBehaviourWithObjectField))]
|
||||
[TestCase(typeof(CustomMonoBehaviourWithMonoBehaviourField))]
|
||||
[TestCase(typeof(CustomMonoBehaviourWithNonGenericDerivedMonoBehaviourField))]
|
||||
[TestCase(typeof(CustomMonoBehaviourWithGenericAbstractMonoBehaviourField))]
|
||||
public void DeserializationSupportsPPtrFields(Type type)
|
||||
{
|
||||
SerializableType serializableType = SerializableTypes.Create(type);
|
||||
Assert.That(serializableType.Fields, Has.Count.EqualTo(1));
|
||||
SerializableType.Field field = serializableType.Fields[0];
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
Assert.That(field.Type, Is.EqualTo(SerializablePointerType.Shared));
|
||||
Assert.That(field.ArrayDepth, Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D3? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3()
|
||||
{
|
||||
List<SerializableType> serializableType = CreateSerializableTypes<CyclicalReferenceClass_C1_D3>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D4? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D4? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C4_D4? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C4_D4
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D4? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D4()
|
||||
{
|
||||
List<SerializableType> serializableType = CreateSerializableTypes<CyclicalReferenceClass_C1_D4>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3_V1
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3_V1? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3_V1
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D3_V1? reference1;
|
||||
public CyclicalReferenceClass_C3_D3_V1? reference2;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3_V1
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V1? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3_V1()
|
||||
{
|
||||
// Variant 1: Two references to the same class
|
||||
List<SerializableType> serializableType = CreateSerializableTypes<CyclicalReferenceClass_C1_D3_V1>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3_V2
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3_V2? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3_V2
|
||||
{
|
||||
public CyclicalReferenceClass_C3_D3_V2? reference1;
|
||||
public CyclicalReferenceClass_C1_D3_V2? reference2;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3_V2
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V2? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3_V2()
|
||||
{
|
||||
// Variant 2: Reference to child class, then reference to parent class
|
||||
List<SerializableType> serializableType = CreateSerializableTypes<CyclicalReferenceClass_C1_D3_V2>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C1_D3_V3
|
||||
{
|
||||
public CyclicalReferenceClass_C2_D3_V3? reference;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C2_D3_V3
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V3? reference1;
|
||||
public CyclicalReferenceClass_C3_D3_V3? reference2;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class CyclicalReferenceClass_C3_D3_V3
|
||||
{
|
||||
public CyclicalReferenceClass_C1_D3_V3? reference;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CyclicalReferenceClassIsHandled_D3_V3()
|
||||
{
|
||||
// Variant 3: Reference to parent class, then reference to child class
|
||||
List<SerializableType> serializableType = CreateSerializableTypes<CyclicalReferenceClass_C1_D3_V3>();
|
||||
using (Assert.EnterMultipleScope())
|
||||
{
|
||||
foreach (SerializableType type in serializableType)
|
||||
{
|
||||
Assert.That(type.Fields, Has.Count.EqualTo(0), $"{type.Name} should have no fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SerializableType CreateSerializableType<T>() => CreateSerializableType<T>(DefaultUnityVersion);
|
||||
|
||||
private static SerializableType CreateSerializableType<T>(UnityVersion version)
|
||||
{
|
||||
TypeDefinition typeDefinition = ReferenceAssemblies.GetType<T>();
|
||||
FieldSerializer serializer = new(version);
|
||||
if (serializer.TryCreateSerializableType(typeDefinition, out SerializableType? serializableType, out string? failureReason))
|
||||
{
|
||||
return serializableType;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail($"Failed to create serializable type: {failureReason}");
|
||||
return default!;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<SerializableType> CreateSerializableTypes<T>() => CreateSerializableTypes<T>(DefaultUnityVersion);
|
||||
|
||||
private static List<SerializableType> CreateSerializableTypes<T>(UnityVersion version)
|
||||
{
|
||||
TypeDefinition typeDefinition = ReferenceAssemblies.GetType<T>();
|
||||
FieldSerializer serializer = new(version);
|
||||
Dictionary<ITypeDefOrRef, SerializableType> typeCache = new();
|
||||
if (serializer.TryCreateSerializableType(typeDefinition, typeCache, out SerializableType? serializableType, out string? failureReason))
|
||||
{
|
||||
return typeCache.Values.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail($"Failed to create serializable type: {failureReason}");
|
||||
return default!;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assume a recent Unity version if not specified.
|
||||
/// </summary>
|
||||
private static UnityVersion DefaultUnityVersion => new(6000);
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
using AssetRipper.Primitives;
|
||||
|
||||
namespace AssetRipper.SerializationLogic.Tests;
|
||||
|
||||
public static class SerializableTypes
|
||||
{
|
||||
public static SerializableType Create<T>() => Create<T>(DefaultUnityVersion);
|
||||
public static SerializableType Create<T>(UnityVersion version) => Create(typeof(T), version);
|
||||
public static SerializableType Create(Type type) => Create(type, DefaultUnityVersion);
|
||||
public static SerializableType Create(Type type, UnityVersion version)
|
||||
{
|
||||
TypeDefinition typeDefinition = ReferenceAssemblies.GetType(type);
|
||||
FieldSerializer serializer = new(version);
|
||||
if (serializer.TryCreateSerializableType(typeDefinition, out SerializableType? serializableType, out string? failureReason))
|
||||
{
|
||||
return serializableType;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail($"Failed to create serializable type: {failureReason}");
|
||||
return default!;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SerializableType> CreateMultiple<T>() => CreateMultiple<T>(DefaultUnityVersion);
|
||||
public static List<SerializableType> CreateMultiple<T>(UnityVersion version) => CreateMultiple(typeof(T), version);
|
||||
public static List<SerializableType> CreateMultiple(Type type) => CreateMultiple(type, DefaultUnityVersion);
|
||||
public static List<SerializableType> CreateMultiple(Type type, UnityVersion version)
|
||||
{
|
||||
TypeDefinition typeDefinition = ReferenceAssemblies.GetType(type);
|
||||
FieldSerializer serializer = new(version);
|
||||
Dictionary<ITypeDefOrRef, SerializableType> typeCache = new();
|
||||
if (serializer.TryCreateSerializableType(typeDefinition, typeCache, out SerializableType? serializableType, out string? failureReason))
|
||||
{
|
||||
return typeCache.Values.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail($"Failed to create serializable type: {failureReason}");
|
||||
return default!;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assume a recent Unity version if not specified.
|
||||
/// </summary>
|
||||
private static UnityVersion DefaultUnityVersion => new(6000);
|
||||
}
|
||||
@ -51,6 +51,11 @@ namespace AssetRipper.SerializationLogic.Extensions
|
||||
// let's assume it is not assignable to our target type
|
||||
}
|
||||
|
||||
public static bool InheritsFromObject(this ITypeDescriptor type)
|
||||
{
|
||||
return type.IsAssignableTo("UnityEngine", "Object");
|
||||
}
|
||||
|
||||
public static bool IsEnum(this ITypeDescriptor type)
|
||||
{
|
||||
return type.IsValueType && !type.IsPrimitive() && type.CheckedResolve().IsEnum;
|
||||
|
||||
@ -241,7 +241,13 @@ public readonly struct FieldSerializer(UnityVersion version)
|
||||
return TryCreateSerializableField(typeStack, name, szArrayTypeSignature.BaseType, arrayDepth + 1, typeCache, out result, out failureReason);
|
||||
|
||||
case GenericInstanceTypeSignature genericInstanceTypeSignature:
|
||||
if (typeCache.TryGetValue(genericInstanceTypeSignature.ToTypeDefOrRef(), out SerializableType? cachedGenericMonoType))
|
||||
if (genericInstanceTypeSignature.InheritsFromObject())
|
||||
{
|
||||
result = new Field(SerializablePointerType.Shared, arrayDepth, name, true);
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
else if (typeCache.TryGetValue(genericInstanceTypeSignature.ToTypeDefOrRef(), out SerializableType? cachedGenericMonoType))
|
||||
{
|
||||
result = new Field(cachedGenericMonoType, arrayDepth, name, true);
|
||||
failureReason = null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user