diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj
index 780f4d6..c5d11ce 100644
--- a/AssetStudioUtility/AssetStudioUtility.csproj
+++ b/AssetStudioUtility/AssetStudioUtility.csproj
@@ -34,6 +34,9 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\Mono.Cecil.0.11.3\lib\net40\Mono.Cecil.dll
+
@@ -43,15 +46,6 @@
-
- Libraries\Unity.Cecil.dll
-
-
- Libraries\Unity.CecilTools.dll
-
-
- Libraries\Unity.SerializationLogic.dll
-
@@ -85,6 +79,14 @@
+
+
+
+
+
+
+
+
@@ -104,5 +106,8 @@
Texture2DDecoderWrapper
+
+
+
\ No newline at end of file
diff --git a/AssetStudioUtility/Libraries/Unity.Cecil.dll b/AssetStudioUtility/Libraries/Unity.Cecil.dll
deleted file mode 100644
index 4166cfc..0000000
Binary files a/AssetStudioUtility/Libraries/Unity.Cecil.dll and /dev/null differ
diff --git a/AssetStudioUtility/Libraries/Unity.CecilTools.dll b/AssetStudioUtility/Libraries/Unity.CecilTools.dll
deleted file mode 100644
index 2c1ce70..0000000
Binary files a/AssetStudioUtility/Libraries/Unity.CecilTools.dll and /dev/null differ
diff --git a/AssetStudioUtility/Libraries/Unity.SerializationLogic.dll b/AssetStudioUtility/Libraries/Unity.SerializationLogic.dll
deleted file mode 100644
index 7af54d9..0000000
Binary files a/AssetStudioUtility/Libraries/Unity.SerializationLogic.dll and /dev/null differ
diff --git a/AssetStudioUtility/TypeDefinitionConverter.cs b/AssetStudioUtility/TypeDefinitionConverter.cs
index d796f0e..28f4f03 100644
--- a/AssetStudioUtility/TypeDefinitionConverter.cs
+++ b/AssetStudioUtility/TypeDefinitionConverter.cs
@@ -26,22 +26,22 @@ namespace AssetStudio
{
var nodes = new List();
- Stack baseTypes = new Stack();
- TypeReference baseType = TypeDef.BaseType;
- while (!UnitySerializationLogic.IsNonSerialized(baseType))
+ var baseTypes = new Stack();
+ var lastBaseType = TypeDef.BaseType;
+ while (!UnitySerializationLogic.IsNonSerialized(lastBaseType))
{
- GenericInstanceType genericInstanceType = baseType as GenericInstanceType;
+ var genericInstanceType = lastBaseType as GenericInstanceType;
if (genericInstanceType != null)
{
TypeResolver.Add(genericInstanceType);
}
- baseTypes.Push(baseType);
- baseType = baseType.Resolve().BaseType;
+ baseTypes.Push(lastBaseType);
+ lastBaseType = lastBaseType.Resolve().BaseType;
}
while (baseTypes.Count > 0)
{
- TypeReference typeReference = baseTypes.Pop();
- TypeDefinition typeDefinition = typeReference.Resolve();
+ var typeReference = baseTypes.Pop();
+ var typeDefinition = typeReference.Resolve();
foreach (var fieldDefinition in typeDefinition.Fields.Where(WillUnitySerialize))
{
if (!IsHiddenByParentClass(baseTypes, fieldDefinition, TypeDef))
@@ -50,15 +50,15 @@ namespace AssetStudio
}
}
- var genericInstanceType2 = typeReference as GenericInstanceType;
- if (genericInstanceType2 != null)
+ var genericInstanceType = typeReference as GenericInstanceType;
+ if (genericInstanceType != null)
{
- TypeResolver.Remove(genericInstanceType2);
+ TypeResolver.Remove(genericInstanceType);
}
}
- foreach (FieldDefinition fieldDefinition2 in FilteredFields())
+ foreach (var field in FilteredFields())
{
- nodes.AddRange(ProcessingFieldRef(fieldDefinition2));
+ nodes.AddRange(ProcessingFieldRef(field));
}
return nodes;
@@ -66,75 +66,60 @@ namespace AssetStudio
private bool WillUnitySerialize(FieldDefinition fieldDefinition)
{
- bool result;
try
{
- TypeReference typeReference = TypeResolver.Resolve(fieldDefinition.FieldType);
- if (UnitySerializationLogic.ShouldNotTryToResolve(typeReference))
+ var resolvedFieldType = TypeResolver.Resolve(fieldDefinition.FieldType);
+ if (UnitySerializationLogic.ShouldNotTryToResolve(resolvedFieldType))
{
- result = false;
+ return false;
}
- else
+ if (!UnityEngineTypePredicates.IsUnityEngineObject(resolvedFieldType))
{
- if (!UnityEngineTypePredicates.IsUnityEngineObject(typeReference))
+ if (resolvedFieldType.FullName == fieldDefinition.DeclaringType.FullName)
{
- if (typeReference.FullName == fieldDefinition.DeclaringType.FullName)
- {
- return false;
- }
+ return false;
}
- result = UnitySerializationLogic.WillUnitySerialize(fieldDefinition, TypeResolver);
}
+ return UnitySerializationLogic.WillUnitySerialize(fieldDefinition, TypeResolver);
}
catch (Exception ex)
{
throw new Exception(string.Format("Exception while processing {0} {1}, error {2}", fieldDefinition.FieldType.FullName, fieldDefinition.FullName, ex.Message));
}
- return result;
}
private static bool IsHiddenByParentClass(IEnumerable parentTypes, FieldDefinition fieldDefinition, TypeDefinition processingType)
{
- return processingType.Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name) || parentTypes.Any((TypeReference t) => t.Resolve().Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name));
+ return processingType.Fields.Any(f => f.Name == fieldDefinition.Name) || parentTypes.Any(t => t.Resolve().Fields.Any(f => f.Name == fieldDefinition.Name));
}
private IEnumerable FilteredFields()
{
- foreach (var f in TypeDef.Fields.Where(WillUnitySerialize))
- {
- if (UnitySerializationLogic.IsSupportedCollection(f.FieldType) || !f.FieldType.IsGenericInstance || UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve()))
- {
- yield return f;
- }
- }
-
- yield break;
+ return TypeDef.Fields.Where(WillUnitySerialize).Where(f =>
+ UnitySerializationLogic.IsSupportedCollection(f.FieldType) ||
+ !f.FieldType.IsGenericInstance ||
+ UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve()));
}
private FieldReference ResolveGenericFieldReference(FieldReference fieldRef)
{
- FieldReference field = new FieldReference(fieldRef.Name, fieldRef.FieldType, ResolveDeclaringType(fieldRef.DeclaringType));
+ var field = new FieldReference(fieldRef.Name, fieldRef.FieldType, ResolveDeclaringType(fieldRef.DeclaringType));
return TypeDef.Module.ImportReference(field);
}
private TypeReference ResolveDeclaringType(TypeReference declaringType)
{
- TypeDefinition typeDefinition = declaringType.Resolve();
- TypeReference result;
+ var typeDefinition = declaringType.Resolve();
if (typeDefinition == null || !typeDefinition.HasGenericParameters)
{
- result = typeDefinition;
+ return typeDefinition;
}
- else
+ var genericInstanceType = new GenericInstanceType(typeDefinition);
+ foreach (var genericParameter in typeDefinition.GenericParameters)
{
- GenericInstanceType genericInstanceType = new GenericInstanceType(typeDefinition);
- foreach (GenericParameter item in typeDefinition.GenericParameters)
- {
- genericInstanceType.GenericArguments.Add(item);
- }
- result = TypeResolver.Resolve(genericInstanceType);
+ genericInstanceType.GenericArguments.Add(genericParameter);
}
- return result;
+ return TypeResolver.Resolve(genericInstanceType);
}
private List ProcessingFieldRef(FieldReference fieldDef)
@@ -155,7 +140,6 @@ namespace AssetStudio
private static bool RequiresAlignment(TypeReference typeRef)
{
- bool result;
switch (typeRef.MetadataType)
{
case MetadataType.Boolean:
@@ -164,13 +148,10 @@ namespace AssetStudio
case MetadataType.Byte:
case MetadataType.Int16:
case MetadataType.UInt16:
- result = true;
- break;
+ return true;
default:
- result = (UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef)));
- break;
+ return UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef));
}
- return result;
}
private static bool IsSystemString(TypeReference typeRef)
diff --git a/AssetStudioUtility/Unity.CecilTools/CecilUtils.cs b/AssetStudioUtility/Unity.CecilTools/CecilUtils.cs
new file mode 100644
index 0000000..a7e3cb0
--- /dev/null
+++ b/AssetStudioUtility/Unity.CecilTools/CecilUtils.cs
@@ -0,0 +1,65 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Unity.CecilTools.Extensions;
+
+namespace Unity.CecilTools
+{
+ public static class CecilUtils
+ {
+ public static MethodDefinition FindInTypeExplicitImplementationFor(MethodDefinition interfaceMethod, TypeDefinition typeDefinition)
+ {
+ return typeDefinition.Methods.SingleOrDefault(m => m.Overrides.Any(o => o.CheckedResolve().SameAs(interfaceMethod)));
+ }
+
+ public static IEnumerable AllInterfacesImplementedBy(TypeDefinition typeDefinition)
+ {
+ return TypeAndBaseTypesOf(typeDefinition).SelectMany(t => t.Interfaces).Select(i => i.InterfaceType.CheckedResolve()).Distinct();
+ }
+
+ public static IEnumerable TypeAndBaseTypesOf(TypeReference typeReference)
+ {
+ while (typeReference != null)
+ {
+ var typeDefinition = typeReference.CheckedResolve();
+ yield return typeDefinition;
+ typeReference = typeDefinition.BaseType;
+ }
+ }
+
+ public static IEnumerable BaseTypesOf(TypeReference typeReference)
+ {
+ return TypeAndBaseTypesOf(typeReference).Skip(1);
+ }
+
+ public static bool IsGenericList(TypeReference type)
+ {
+ return type.Name == "List`1" && type.SafeNamespace() == "System.Collections.Generic";
+ }
+
+ public static bool IsGenericDictionary(TypeReference type)
+ {
+ if (type is GenericInstanceType)
+ type = ((GenericInstanceType)type).ElementType;
+
+ return type.Name == "Dictionary`2" && type.SafeNamespace() == "System.Collections.Generic";
+ }
+
+ public static TypeReference ElementTypeOfCollection(TypeReference type)
+ {
+ var at = type as ArrayType;
+ if (at != null)
+ return at.ElementType;
+
+ if (IsGenericList(type))
+ return ((GenericInstanceType)type).GenericArguments.Single();
+
+ throw new ArgumentException();
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.CecilTools/ElementType.cs b/AssetStudioUtility/Unity.CecilTools/ElementType.cs
new file mode 100644
index 0000000..a3d858d
--- /dev/null
+++ b/AssetStudioUtility/Unity.CecilTools/ElementType.cs
@@ -0,0 +1,21 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System;
+using Mono.Cecil;
+
+namespace Unity.CecilTools
+{
+ static public class ElementType
+ {
+ public static TypeReference For(TypeReference byRefType)
+ {
+ var refType = byRefType as TypeSpecification;
+ if (refType != null)
+ return refType.ElementType;
+
+ throw new ArgumentException(string.Format("TypeReference isn't a TypeSpecification {0} ", byRefType));
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.CecilTools/Extensions/MethodDefinitionExtensions.cs b/AssetStudioUtility/Unity.CecilTools/Extensions/MethodDefinitionExtensions.cs
new file mode 100644
index 0000000..c99d8e7
--- /dev/null
+++ b/AssetStudioUtility/Unity.CecilTools/Extensions/MethodDefinitionExtensions.cs
@@ -0,0 +1,50 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using Mono.Cecil;
+
+namespace Unity.CecilTools.Extensions
+{
+ static class MethodDefinitionExtensions
+ {
+ public static bool SameAs(this MethodDefinition self, MethodDefinition other)
+ {
+ // FIXME: should be able to compare MethodDefinition references directly
+ return self.FullName == other.FullName;
+ }
+
+ public static string PropertyName(this MethodDefinition self)
+ {
+ return self.Name.Substring(4);
+ }
+
+ public static bool IsConversionOperator(this MethodDefinition method)
+ {
+ if (!method.IsSpecialName)
+ return false;
+
+ return method.Name == "op_Implicit" || method.Name == "op_Explicit";
+ }
+
+ public static bool IsSimpleSetter(this MethodDefinition original)
+ {
+ return original.IsSetter && original.Parameters.Count == 1;
+ }
+
+ public static bool IsSimpleGetter(this MethodDefinition original)
+ {
+ return original.IsGetter && original.Parameters.Count == 0;
+ }
+
+ public static bool IsSimplePropertyAccessor(this MethodDefinition method)
+ {
+ return method.IsSimpleGetter() || method.IsSimpleSetter();
+ }
+
+ public static bool IsDefaultConstructor(MethodDefinition m)
+ {
+ return m.IsConstructor && !m.IsStatic && m.Parameters.Count == 0;
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.CecilTools/Extensions/ResolutionExtensions.cs b/AssetStudioUtility/Unity.CecilTools/Extensions/ResolutionExtensions.cs
new file mode 100644
index 0000000..29d8506
--- /dev/null
+++ b/AssetStudioUtility/Unity.CecilTools/Extensions/ResolutionExtensions.cs
@@ -0,0 +1,36 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System;
+using Mono.Cecil;
+
+namespace Unity.CecilTools.Extensions
+{
+ public static class ResolutionExtensions
+ {
+ public static TypeDefinition CheckedResolve(this TypeReference type)
+ {
+ return Resolve(type, reference => reference.Resolve());
+ }
+
+ public static MethodDefinition CheckedResolve(this MethodReference method)
+ {
+ return Resolve(method, reference => reference.Resolve());
+ }
+
+ private static TDefinition Resolve(TReference reference, Func resolve)
+ where TReference : MemberReference
+ where TDefinition : class, IMemberDefinition
+ {
+ if (reference.Module == null)
+ throw new ResolutionException(reference);
+
+ var definition = resolve(reference);
+ if (definition == null)
+ throw new ResolutionException(reference);
+
+ return definition;
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.CecilTools/Extensions/TypeDefinitionExtensions.cs b/AssetStudioUtility/Unity.CecilTools/Extensions/TypeDefinitionExtensions.cs
new file mode 100644
index 0000000..fea4610
--- /dev/null
+++ b/AssetStudioUtility/Unity.CecilTools/Extensions/TypeDefinitionExtensions.cs
@@ -0,0 +1,47 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Mono.Cecil;
+
+namespace Unity.CecilTools.Extensions
+{
+ public static class TypeDefinitionExtensions
+ {
+ public static bool IsSubclassOf(this TypeDefinition type, string baseTypeName)
+ {
+ var baseType = type.BaseType;
+ if (baseType == null)
+ return false;
+ if (baseType.FullName == baseTypeName)
+ return true;
+
+ var baseTypeDef = baseType.Resolve();
+ if (baseTypeDef == null)
+ return false;
+
+ return IsSubclassOf(baseTypeDef, baseTypeName);
+ }
+
+ public static bool IsSubclassOf(this TypeDefinition type, params string[] baseTypeNames)
+ {
+ var baseType = type.BaseType;
+ if (baseType == null)
+ return false;
+
+ for (int i = 0; i < baseTypeNames.Length; i++)
+ if (baseType.FullName == baseTypeNames[i])
+ return true;
+
+ var baseTypeDef = baseType.Resolve();
+ if (baseTypeDef == null)
+ return false;
+
+ return IsSubclassOf(baseTypeDef, baseTypeNames);
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.CecilTools/Extensions/TypeReferenceExtensions.cs b/AssetStudioUtility/Unity.CecilTools/Extensions/TypeReferenceExtensions.cs
new file mode 100644
index 0000000..65bf501
--- /dev/null
+++ b/AssetStudioUtility/Unity.CecilTools/Extensions/TypeReferenceExtensions.cs
@@ -0,0 +1,53 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using Mono.Cecil;
+
+namespace Unity.CecilTools.Extensions
+{
+ public static class TypeReferenceExtensions
+ {
+ public static string SafeNamespace(this TypeReference type)
+ {
+ if (type.IsGenericInstance)
+ return ((GenericInstanceType)type).ElementType.SafeNamespace();
+ if (type.IsNested)
+ return type.DeclaringType.SafeNamespace();
+ return type.Namespace;
+ }
+
+ public static bool IsAssignableTo(this TypeReference typeRef, string typeName)
+ {
+ try
+ {
+ if (typeRef.IsGenericInstance)
+ return ElementType.For(typeRef).IsAssignableTo(typeName);
+
+ if (typeRef.FullName == typeName)
+ return true;
+
+ return typeRef.CheckedResolve().IsSubclassOf(typeName);
+ }
+ catch (AssemblyResolutionException) // If we can't resolve our typeref or one of its base types,
+ { // let's assume it is not assignable to our target type
+ return false;
+ }
+ }
+
+ public static bool IsEnum(this TypeReference type)
+ {
+ return type.IsValueType && !type.IsPrimitive && type.CheckedResolve().IsEnum;
+ }
+
+ public static bool IsStruct(this TypeReference type)
+ {
+ return type.IsValueType && !type.IsPrimitive && !type.IsEnum() && !IsSystemDecimal(type);
+ }
+
+ private static bool IsSystemDecimal(TypeReference type)
+ {
+ return type.FullName == "System.Decimal";
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.SerializationLogic/UnityEngineTypePredicates.cs b/AssetStudioUtility/Unity.SerializationLogic/UnityEngineTypePredicates.cs
new file mode 100644
index 0000000..73e39ee
--- /dev/null
+++ b/AssetStudioUtility/Unity.SerializationLogic/UnityEngineTypePredicates.cs
@@ -0,0 +1,168 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System.Collections.Generic;
+using Unity.CecilTools.Extensions;
+using Mono.Cecil;
+
+namespace Unity.SerializationLogic
+{
+ public class UnityEngineTypePredicates
+ {
+ private static readonly HashSet TypesThatShouldHaveHadSerializableAttribute = new HashSet
+ {
+ "Vector3",
+ "Vector2",
+ "Vector4",
+ "Rect",
+ "RectInt",
+ "Quaternion",
+ "Matrix4x4",
+ "Color",
+ "Color32",
+ "LayerMask",
+ "Bounds",
+ "BoundsInt",
+ "Vector3Int",
+ "Vector2Int",
+ };
+
+ private const string Gradient = "UnityEngine.Gradient";
+ private const string GUIStyle = "UnityEngine.GUIStyle";
+ private const string RectOffset = "UnityEngine.RectOffset";
+ protected const string UnityEngineObject = "UnityEngine.Object";
+ public const string MonoBehaviour = "UnityEngine.MonoBehaviour";
+ public const string ScriptableObject = "UnityEngine.ScriptableObject";
+ protected const string Matrix4x4 = "UnityEngine.Matrix4x4";
+ protected const string Color32 = "UnityEngine.Color32";
+ private const string SerializeFieldAttribute = "UnityEngine.SerializeField";
+ private const string SerializeReferenceAttribute = "UnityEngine.SerializeReference";
+
+ private static string[] serializableClasses = new[]
+ {
+ "UnityEngine.AnimationCurve",
+ "UnityEngine.Gradient",
+ "UnityEngine.GUIStyle",
+ "UnityEngine.RectOffset"
+ };
+
+ private static string[] serializableStructs = new[]
+ {
+ // NOTE: assumes all types here are NOT interfaces
+ "UnityEngine.Color32",
+ "UnityEngine.Matrix4x4",
+ "UnityEngine.Rendering.SphericalHarmonicsL2",
+ "UnityEngine.PropertyName",
+ };
+
+ public static bool IsMonoBehaviour(TypeReference type)
+ {
+ return IsMonoBehaviour(type.CheckedResolve());
+ }
+
+ private static bool IsMonoBehaviour(TypeDefinition typeDefinition)
+ {
+ return typeDefinition.IsSubclassOf(MonoBehaviour);
+ }
+
+ public static bool IsScriptableObject(TypeReference type)
+ {
+ return IsScriptableObject(type.CheckedResolve());
+ }
+
+ private static bool IsScriptableObject(TypeDefinition temp)
+ {
+ return temp.IsSubclassOf(ScriptableObject);
+ }
+
+ public static bool IsColor32(TypeReference type)
+ {
+ return type.IsAssignableTo(Color32);
+ }
+
+ //Do NOT remove these, cil2as still depends on these in 4.x
+ public static bool IsMatrix4x4(TypeReference type)
+ {
+ return type.IsAssignableTo(Matrix4x4);
+ }
+
+ public static bool IsGradient(TypeReference type)
+ {
+ return type.IsAssignableTo(Gradient);
+ }
+
+ public static bool IsGUIStyle(TypeReference type)
+ {
+ return type.IsAssignableTo(GUIStyle);
+ }
+
+ public static bool IsRectOffset(TypeReference type)
+ {
+ return type.IsAssignableTo(RectOffset);
+ }
+
+ public static bool IsSerializableUnityClass(TypeReference type)
+ {
+ foreach (var unityClasses in serializableClasses)
+ {
+ if (type.IsAssignableTo(unityClasses))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsSerializableUnityStruct(TypeReference type)
+ {
+ foreach (var unityStruct in serializableStructs)
+ {
+ // NOTE: structs cannot inherit from structs, and can only inherit from interfaces
+ // since we know all types in serializableStructs are not interfaces,
+ // we can just do a direct comparison.
+ if (type.FullName == unityStruct)
+ return true;
+ }
+
+ if (type.FullName.IndexOf("UnityEngine.LazyLoadReference`1") == 0)
+ return true;
+
+ return false;
+ }
+
+ public static bool IsUnityEngineObject(TypeReference type)
+ {
+ //todo: somehow solve this elegantly. CheckedResolve() drops the [] of a type.
+ if (type.IsArray)
+ return false;
+
+ if (type.FullName == UnityEngineObject)
+ return true;
+
+ var typeDefinition = type.Resolve();
+ if (typeDefinition == null)
+ return false;
+
+ return typeDefinition.IsSubclassOf(UnityEngineObject);
+ }
+
+ public static bool ShouldHaveHadSerializableAttribute(TypeReference type)
+ {
+ return IsUnityEngineValueType(type);
+ }
+
+ public static bool IsUnityEngineValueType(TypeReference type)
+ {
+ return type.SafeNamespace() == "UnityEngine" && TypesThatShouldHaveHadSerializableAttribute.Contains(type.Name);
+ }
+
+ public static bool IsSerializeFieldAttribute(TypeReference attributeType)
+ {
+ return attributeType.FullName == SerializeFieldAttribute;
+ }
+
+ public static bool IsSerializeReferenceAttribute(TypeReference attributeType)
+ {
+ return attributeType.FullName == SerializeReferenceAttribute;
+ }
+ }
+}
diff --git a/AssetStudioUtility/Unity.SerializationLogic/UnitySerializationLogic.cs b/AssetStudioUtility/Unity.SerializationLogic/UnitySerializationLogic.cs
new file mode 100644
index 0000000..1d141ab
--- /dev/null
+++ b/AssetStudioUtility/Unity.SerializationLogic/UnitySerializationLogic.cs
@@ -0,0 +1,612 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Collections.Generic;
+using Unity.CecilTools;
+using Unity.CecilTools.Extensions;
+
+namespace Unity.SerializationLogic
+{
+ internal class GenericInstanceHolder
+ {
+ public int Count;
+ public IGenericInstance GenericInstance;
+ }
+
+ public class TypeResolver
+ {
+ private readonly IGenericInstance _typeDefinitionContext;
+ private readonly IGenericInstance _methodDefinitionContext;
+ private readonly Dictionary _context = new Dictionary();
+
+ public TypeResolver()
+ {
+ }
+
+ public TypeResolver(IGenericInstance typeDefinitionContext)
+ {
+ _typeDefinitionContext = typeDefinitionContext;
+ }
+
+ public TypeResolver(GenericInstanceMethod methodDefinitionContext)
+ {
+ _methodDefinitionContext = methodDefinitionContext;
+ }
+
+ public TypeResolver(IGenericInstance typeDefinitionContext, IGenericInstance methodDefinitionContext)
+ {
+ _typeDefinitionContext = typeDefinitionContext;
+ _methodDefinitionContext = methodDefinitionContext;
+ }
+
+ public void Add(GenericInstanceType genericInstanceType)
+ {
+ Add(ElementTypeFor(genericInstanceType).FullName, genericInstanceType);
+ }
+
+ public void Remove(GenericInstanceType genericInstanceType)
+ {
+ Remove(genericInstanceType.ElementType.FullName, genericInstanceType);
+ }
+
+ public void Add(GenericInstanceMethod genericInstanceMethod)
+ {
+ Add(ElementTypeFor(genericInstanceMethod).FullName, genericInstanceMethod);
+ }
+
+ private static MemberReference ElementTypeFor(TypeSpecification genericInstanceType)
+ {
+ return genericInstanceType.ElementType;
+ }
+
+ private static MemberReference ElementTypeFor(MethodSpecification genericInstanceMethod)
+ {
+ return genericInstanceMethod.ElementMethod;
+ }
+
+ public void Remove(GenericInstanceMethod genericInstanceMethod)
+ {
+ Remove(genericInstanceMethod.ElementMethod.FullName, genericInstanceMethod);
+ }
+
+ public TypeReference Resolve(TypeReference typeReference)
+ {
+ var genericParameter = typeReference as GenericParameter;
+ if (genericParameter != null)
+ {
+ var resolved = ResolveGenericParameter(genericParameter);
+ if (genericParameter == resolved) // Resolving failed, return what we have.
+ return resolved;
+
+ return Resolve(resolved);
+ }
+
+ var arrayType = typeReference as ArrayType;
+ if (arrayType != null)
+ return new ArrayType(Resolve(arrayType.ElementType), arrayType.Rank);
+
+ var pointerType = typeReference as PointerType;
+ if (pointerType != null)
+ return new PointerType(Resolve(pointerType.ElementType));
+
+ var byReferenceType = typeReference as ByReferenceType;
+ if (byReferenceType != null)
+ return new ByReferenceType(Resolve(byReferenceType.ElementType));
+
+ var genericInstanceType = typeReference as GenericInstanceType;
+ if (genericInstanceType != null)
+ {
+ var newGenericInstanceType = new GenericInstanceType(Resolve(genericInstanceType.ElementType));
+ foreach (var genericArgument in genericInstanceType.GenericArguments)
+ newGenericInstanceType.GenericArguments.Add(Resolve(genericArgument));
+ return newGenericInstanceType;
+ }
+
+ var pinnedType = typeReference as PinnedType;
+ if (pinnedType != null)
+ return new PinnedType(Resolve(pinnedType.ElementType));
+
+ var reqModifierType = typeReference as RequiredModifierType;
+ if (reqModifierType != null)
+ return Resolve(reqModifierType.ElementType);
+
+ var optModifierType = typeReference as OptionalModifierType;
+ if (optModifierType != null)
+ return new OptionalModifierType(Resolve(optModifierType.ModifierType), Resolve(optModifierType.ElementType));
+
+ var sentinelType = typeReference as SentinelType;
+ if (sentinelType != null)
+ return new SentinelType(Resolve(sentinelType.ElementType));
+
+ var funcPtrType = typeReference as FunctionPointerType;
+ if (funcPtrType != null)
+ throw new NotSupportedException("Function pointer types are not supported by the SerializationWeaver");
+
+ if (typeReference is TypeSpecification)
+ throw new NotSupportedException();
+
+ return typeReference;
+ }
+
+ private TypeReference ResolveGenericParameter(GenericParameter genericParameter)
+ {
+ if (genericParameter.Owner == null)
+ throw new NotSupportedException();
+
+ var memberReference = genericParameter.Owner as MemberReference;
+ if (memberReference == null)
+ throw new NotSupportedException();
+
+ var key = memberReference.FullName;
+ if (!_context.ContainsKey(key))
+ {
+ if (genericParameter.Type == GenericParameterType.Type)
+ {
+ if (_typeDefinitionContext != null)
+ return _typeDefinitionContext.GenericArguments[genericParameter.Position];
+
+ return genericParameter;
+ }
+
+ if (_methodDefinitionContext != null)
+ return _methodDefinitionContext.GenericArguments[genericParameter.Position];
+
+ return genericParameter;
+ }
+
+ return GenericArgumentAt(key, genericParameter.Position);
+ }
+
+ private TypeReference GenericArgumentAt(string key, int position)
+ {
+ return _context[key].GenericInstance.GenericArguments[position];
+ }
+
+ private void Add(string key, IGenericInstance value)
+ {
+ GenericInstanceHolder oldValue;
+
+ if (_context.TryGetValue(key, out oldValue))
+ {
+ var memberReference = value as MemberReference;
+ if (memberReference == null)
+ throw new NotSupportedException();
+
+ var storedValue = (MemberReference)oldValue.GenericInstance;
+
+ if (storedValue.FullName != memberReference.FullName)
+ throw new ArgumentException("Duplicate key!", "key");
+
+ oldValue.Count++;
+ return;
+ }
+
+ _context.Add(key, new GenericInstanceHolder { Count = 1, GenericInstance = value });
+ }
+
+ private void Remove(string key, IGenericInstance value)
+ {
+ GenericInstanceHolder oldValue;
+
+ if (_context.TryGetValue(key, out oldValue))
+ {
+ var memberReference = value as MemberReference;
+ if (memberReference == null)
+ throw new NotSupportedException();
+
+ var storedValue = (MemberReference)oldValue.GenericInstance;
+
+ if (storedValue.FullName != memberReference.FullName)
+ throw new ArgumentException("Invalid value!", "value");
+
+ oldValue.Count--;
+ if (oldValue.Count == 0)
+ _context.Remove(key);
+
+ return;
+ }
+
+ throw new ArgumentException("Invalid key!", "key");
+ }
+ }
+
+ public static class UnitySerializationLogic
+ {
+ public static bool WillUnitySerialize(FieldDefinition fieldDefinition)
+ {
+ return WillUnitySerialize(fieldDefinition, new TypeResolver(null));
+ }
+
+ public static bool WillUnitySerialize(FieldDefinition fieldDefinition, TypeResolver typeResolver)
+ {
+ if (fieldDefinition == null)
+ return false;
+
+ //skip static, const and NotSerialized fields before even checking the type
+ if (fieldDefinition.IsStatic || IsConst(fieldDefinition) || fieldDefinition.IsNotSerialized || fieldDefinition.IsInitOnly)
+ return false;
+
+ // The field must have correct visibility/decoration to be serialized.
+ if (!fieldDefinition.IsPublic &&
+ !ShouldHaveHadAllFieldsPublic(fieldDefinition) &&
+ !HasSerializeFieldAttribute(fieldDefinition) &&
+ !HasSerializeReferenceAttribute(fieldDefinition))
+ return false;
+
+ // Don't try to resolve types that come from Windows assembly,
+ // as serialization weaver will fail to resolve that (due to it being in platform specific SDKs)
+ if (ShouldNotTryToResolve(fieldDefinition.FieldType))
+ return false;
+
+ if (IsFixedBuffer(fieldDefinition))
+ return true;
+
+ // Resolving types is more complex and slower than checking their names or attributes,
+ // thus keep those checks below
+ var typeReference = typeResolver.Resolve(fieldDefinition.FieldType);
+
+ //the type of the field must be serializable in the first place.
+
+ if (typeReference.MetadataType == MetadataType.String)
+ return true;
+
+ if (typeReference.IsValueType)
+ return IsValueTypeSerializable(typeReference);
+
+ if (typeReference is ArrayType || CecilUtils.IsGenericList(typeReference))
+ {
+ if (!HasSerializeReferenceAttribute(fieldDefinition))
+ return IsSupportedCollection(typeReference);
+ }
+
+
+ if (!IsReferenceTypeSerializable(typeReference) && !HasSerializeReferenceAttribute(fieldDefinition))
+ return false;
+
+ if (IsDelegate(typeReference))
+ return false;
+
+ return true;
+ }
+
+ private static bool IsDelegate(TypeReference typeReference)
+ {
+ return typeReference.IsAssignableTo("System.Delegate");
+ }
+
+ public static bool ShouldFieldBePPtrRemapped(FieldDefinition fieldDefinition)
+ {
+ return ShouldFieldBePPtrRemapped(fieldDefinition, new TypeResolver(null));
+ }
+
+ public static bool ShouldFieldBePPtrRemapped(FieldDefinition fieldDefinition, TypeResolver typeResolver)
+ {
+ if (!WillUnitySerialize(fieldDefinition, typeResolver))
+ return false;
+
+ return CanTypeContainUnityEngineObjectReference(typeResolver.Resolve(fieldDefinition.FieldType));
+ }
+
+ private static bool CanTypeContainUnityEngineObjectReference(TypeReference typeReference)
+ {
+ if (IsUnityEngineObject(typeReference))
+ return true;
+
+ if (typeReference.IsEnum())
+ return false;
+
+ if (IsSerializablePrimitive(typeReference))
+ return false;
+
+ if (IsSupportedCollection(typeReference))
+ return CanTypeContainUnityEngineObjectReference(CecilUtils.ElementTypeOfCollection(typeReference));
+
+ var definition = typeReference.Resolve();
+ if (definition == null)
+ return false;
+
+ return HasFieldsThatCanContainUnityEngineObjectReferences(definition, new TypeResolver(typeReference as GenericInstanceType));
+ }
+
+ private static bool HasFieldsThatCanContainUnityEngineObjectReferences(TypeDefinition definition, TypeResolver typeResolver)
+ {
+ return AllFieldsFor(definition, typeResolver).Where(kv => kv.Value.Resolve(kv.Key.FieldType).Resolve() != definition).Any(kv => CanFieldContainUnityEngineObjectReference(definition, kv.Key, kv.Value));
+ }
+
+ private static IEnumerable> AllFieldsFor(TypeDefinition definition, TypeResolver typeResolver)
+ {
+ var baseType = definition.BaseType;
+
+ if (baseType != null)
+ {
+ var genericBaseInstanceType = baseType as GenericInstanceType;
+ if (genericBaseInstanceType != null)
+ typeResolver.Add(genericBaseInstanceType);
+ foreach (var kv in AllFieldsFor(baseType.Resolve(), typeResolver))
+ yield return kv;
+ if (genericBaseInstanceType != null)
+ typeResolver.Remove(genericBaseInstanceType);
+ }
+
+ foreach (var fieldDefinition in definition.Fields)
+ yield return new KeyValuePair(fieldDefinition, typeResolver);
+ }
+
+ private static bool CanFieldContainUnityEngineObjectReference(TypeReference typeReference, FieldDefinition t, TypeResolver typeResolver)
+ {
+ if (typeResolver.Resolve(t.FieldType) == typeReference)
+ return false;
+
+ if (!WillUnitySerialize(t, typeResolver))
+ return false;
+
+ if (UnityEngineTypePredicates.IsUnityEngineValueType(typeReference))
+ return false;
+
+ return true;
+ }
+
+ private static bool IsConst(FieldDefinition fieldDefinition)
+ {
+ return fieldDefinition.IsLiteral && !fieldDefinition.IsInitOnly;
+ }
+
+ public static bool HasSerializeFieldAttribute(FieldDefinition field)
+ {
+ //return FieldAttributes(field).Any(UnityEngineTypePredicates.IsSerializeFieldAttribute);
+ foreach (var attribute in FieldAttributes(field))
+ if (UnityEngineTypePredicates.IsSerializeFieldAttribute(attribute))
+ return true;
+ return false;
+ }
+
+ public static bool HasSerializeReferenceAttribute(FieldDefinition field)
+ {
+ foreach (var attribute in FieldAttributes(field))
+ if (UnityEngineTypePredicates.IsSerializeReferenceAttribute(attribute))
+ return true;
+ return false;
+ }
+
+ private static IEnumerable FieldAttributes(FieldDefinition field)
+ {
+ return field.CustomAttributes.Select(_ => _.AttributeType);
+ }
+
+ public static bool ShouldNotTryToResolve(TypeReference typeReference)
+ {
+ var typeReferenceScopeName = typeReference.Scope.Name;
+ if (typeReferenceScopeName == "Windows")
+ {
+ return true;
+ }
+
+ if (typeReferenceScopeName == "mscorlib")
+ {
+ var resolved = typeReference.Resolve();
+ return resolved == null;
+ }
+
+ try
+ { // This will throw an exception if typereference thinks it's referencing a .dll,
+ // but actually there's .winmd file in the current directory. RRW will fix this
+ // at a later step, so we will not try to resolve this type. This is OK, as any
+ // type defined in a winmd cannot be serialized.
+ typeReference.Resolve();
+ }
+ catch
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static bool IsFieldTypeSerializable(TypeReference typeReference, FieldDefinition fieldDefinition)
+ {
+ return IsTypeSerializable(typeReference) || IsSupportedCollection(typeReference) || IsFixedBuffer(fieldDefinition);
+ }
+
+ private static bool IsValueTypeSerializable(TypeReference typeReference)
+ {
+ if (typeReference.IsPrimitive)
+ return IsSerializablePrimitive(typeReference);
+ return UnityEngineTypePredicates.IsSerializableUnityStruct(typeReference) ||
+ typeReference.IsEnum() ||
+ ShouldImplementIDeserializable(typeReference);
+ }
+
+ private static bool IsReferenceTypeSerializable(TypeReference typeReference)
+ {
+ if (typeReference.MetadataType == MetadataType.String)
+ return IsSerializablePrimitive(typeReference);
+
+ if (IsGenericDictionary(typeReference))
+ return false;
+
+ if (IsUnityEngineObject(typeReference) ||
+ ShouldImplementIDeserializable(typeReference) ||
+ UnityEngineTypePredicates.IsSerializableUnityClass(typeReference))
+ return true;
+
+ return false;
+ }
+
+ private static bool IsTypeSerializable(TypeReference typeReference)
+ {
+ if (typeReference.MetadataType == MetadataType.String)
+ return true;
+ if (typeReference.IsValueType)
+ return IsValueTypeSerializable(typeReference);
+ return IsReferenceTypeSerializable(typeReference);
+ }
+
+ private static bool IsGenericDictionary(TypeReference typeReference)
+ {
+ var current = typeReference;
+
+ if (current != null)
+ {
+ if (CecilUtils.IsGenericDictionary(current))
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool IsFixedBuffer(FieldDefinition fieldDefinition)
+ {
+ return GetFixedBufferAttribute(fieldDefinition) != null;
+ }
+
+ public static CustomAttribute GetFixedBufferAttribute(FieldDefinition fieldDefinition)
+ {
+ if (!fieldDefinition.HasCustomAttributes)
+ return null;
+
+ return fieldDefinition.CustomAttributes.SingleOrDefault(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.FixedBufferAttribute");
+ }
+
+ public static int GetFixedBufferLength(FieldDefinition fieldDefinition)
+ {
+ var fixedBufferAttribute = GetFixedBufferAttribute(fieldDefinition);
+
+ if (fixedBufferAttribute == null)
+ throw new ArgumentException(string.Format("Field '{0}' is not a fixed buffer field.", fieldDefinition.FullName));
+
+ var size = (Int32)fixedBufferAttribute.ConstructorArguments[1].Value;
+
+ return size;
+ }
+
+ public static int PrimitiveTypeSize(TypeReference type)
+ {
+ switch (type.MetadataType)
+ {
+ case MetadataType.Boolean:
+ case MetadataType.Byte:
+ case MetadataType.SByte:
+ return 1;
+
+ case MetadataType.Char:
+ case MetadataType.Int16:
+ case MetadataType.UInt16:
+ return 2;
+
+ case MetadataType.Int32:
+ case MetadataType.UInt32:
+ case MetadataType.Single:
+ return 4;
+
+ case MetadataType.Int64:
+ case MetadataType.UInt64:
+ case MetadataType.Double:
+ return 8;
+
+ default:
+ throw new ArgumentException(string.Format("Unsupported {0}", type.MetadataType));
+ }
+ }
+
+ private static bool IsSerializablePrimitive(TypeReference typeReference)
+ {
+ switch (typeReference.MetadataType)
+ {
+ case MetadataType.SByte:
+ case MetadataType.Byte:
+ case MetadataType.Char:
+ case MetadataType.Int16:
+ case MetadataType.UInt16:
+ case MetadataType.Int64:
+ case MetadataType.UInt64:
+ case MetadataType.Int32:
+ case MetadataType.UInt32:
+ case MetadataType.Single:
+ case MetadataType.Double:
+ case MetadataType.Boolean:
+ case MetadataType.String:
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsSupportedCollection(TypeReference typeReference)
+ {
+ if (!(typeReference is ArrayType || CecilUtils.IsGenericList(typeReference)))
+ return false;
+
+ // We don't support arrays like byte[,] etc
+ if (typeReference.IsArray && ((ArrayType)typeReference).Rank > 1)
+ return false;
+
+ return IsTypeSerializable(CecilUtils.ElementTypeOfCollection(typeReference));
+ }
+
+ private static bool ShouldHaveHadAllFieldsPublic(FieldDefinition field)
+ {
+ return UnityEngineTypePredicates.IsUnityEngineValueType(field.DeclaringType);
+ }
+
+ private static bool IsUnityEngineObject(TypeReference typeReference)
+ {
+ return UnityEngineTypePredicates.IsUnityEngineObject(typeReference);
+ }
+
+ public static bool IsNonSerialized(TypeReference typeDeclaration)
+ {
+ if (typeDeclaration == null)
+ return true;
+ if (typeDeclaration.HasGenericParameters)
+ return true;
+ if (typeDeclaration.MetadataType == MetadataType.Object)
+ return true;
+ var fullName = typeDeclaration.FullName;
+ if (fullName.StartsWith("System.")) //can this be done better?
+ return true;
+ if (typeDeclaration.IsArray)
+ return true;
+ if (typeDeclaration.FullName == UnityEngineTypePredicates.MonoBehaviour)
+ return true;
+ if (typeDeclaration.FullName == UnityEngineTypePredicates.ScriptableObject)
+ return true;
+ if (typeDeclaration.IsEnum())
+ return true;
+ return false;
+ }
+
+ public static bool ShouldImplementIDeserializable(TypeReference typeDeclaration)
+ {
+ if (typeDeclaration.FullName == "UnityEngine.ExposedReference`1")
+ return true;
+
+ if (IsNonSerialized(typeDeclaration))
+ return false;
+
+ try
+ {
+ if (UnityEngineTypePredicates.ShouldHaveHadSerializableAttribute(typeDeclaration))
+ return true;
+
+ var resolvedTypeDeclaration = typeDeclaration.CheckedResolve();
+ if (resolvedTypeDeclaration.IsValueType)
+ {
+ return resolvedTypeDeclaration.IsSerializable && !resolvedTypeDeclaration.CustomAttributes.Any(a => a.AttributeType.FullName.Contains("System.Runtime.CompilerServices.CompilerGenerated"));
+ }
+ else
+ {
+ return (resolvedTypeDeclaration.IsSerializable && !resolvedTypeDeclaration.CustomAttributes.Any(a => a.AttributeType.FullName.Contains("System.Runtime.CompilerServices.CompilerGenerated"))) ||
+ resolvedTypeDeclaration.IsSubclassOf(UnityEngineTypePredicates.MonoBehaviour, UnityEngineTypePredicates.ScriptableObject);
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/AssetStudioUtility/packages.config b/AssetStudioUtility/packages.config
new file mode 100644
index 0000000..85c0c98
--- /dev/null
+++ b/AssetStudioUtility/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file