mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
clean up TypeDefinitionConverter code
This commit is contained in:
parent
77a0c9c40a
commit
d963d71b12
@ -34,6 +34,9 @@
|
|||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Mono.Cecil, Version=0.11.3.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Mono.Cecil.0.11.3\lib\net40\Mono.Cecil.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
@ -43,15 +46,6 @@
|
|||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Unity.Cecil">
|
|
||||||
<HintPath>Libraries\Unity.Cecil.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.CecilTools">
|
|
||||||
<HintPath>Libraries\Unity.CecilTools.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.SerializationLogic">
|
|
||||||
<HintPath>Libraries\Unity.SerializationLogic.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AssemblyLoader.cs" />
|
<Compile Include="AssemblyLoader.cs" />
|
||||||
@ -85,6 +79,14 @@
|
|||||||
<Compile Include="SpriteHelper.cs" />
|
<Compile Include="SpriteHelper.cs" />
|
||||||
<Compile Include="Texture2DConverter.cs" />
|
<Compile Include="Texture2DConverter.cs" />
|
||||||
<Compile Include="Texture2DExtensions.cs" />
|
<Compile Include="Texture2DExtensions.cs" />
|
||||||
|
<Compile Include="Unity.CecilTools\CecilUtils.cs" />
|
||||||
|
<Compile Include="Unity.CecilTools\ElementType.cs" />
|
||||||
|
<Compile Include="Unity.CecilTools\Extensions\MethodDefinitionExtensions.cs" />
|
||||||
|
<Compile Include="Unity.CecilTools\Extensions\ResolutionExtensions.cs" />
|
||||||
|
<Compile Include="Unity.CecilTools\Extensions\TypeDefinitionExtensions.cs" />
|
||||||
|
<Compile Include="Unity.CecilTools\Extensions\TypeReferenceExtensions.cs" />
|
||||||
|
<Compile Include="Unity.SerializationLogic\UnityEngineTypePredicates.cs" />
|
||||||
|
<Compile Include="Unity.SerializationLogic\UnitySerializationLogic.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj">
|
<ProjectReference Include="..\AssetStudio.PInvoke\AssetStudio.PInvoke.csproj">
|
||||||
@ -104,5 +106,8 @@
|
|||||||
<Name>Texture2DDecoderWrapper</Name>
|
<Name>Texture2DDecoderWrapper</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -26,22 +26,22 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
var nodes = new List<TypeTreeNode>();
|
var nodes = new List<TypeTreeNode>();
|
||||||
|
|
||||||
Stack<TypeReference> baseTypes = new Stack<TypeReference>();
|
var baseTypes = new Stack<TypeReference>();
|
||||||
TypeReference baseType = TypeDef.BaseType;
|
var lastBaseType = TypeDef.BaseType;
|
||||||
while (!UnitySerializationLogic.IsNonSerialized(baseType))
|
while (!UnitySerializationLogic.IsNonSerialized(lastBaseType))
|
||||||
{
|
{
|
||||||
GenericInstanceType genericInstanceType = baseType as GenericInstanceType;
|
var genericInstanceType = lastBaseType as GenericInstanceType;
|
||||||
if (genericInstanceType != null)
|
if (genericInstanceType != null)
|
||||||
{
|
{
|
||||||
TypeResolver.Add(genericInstanceType);
|
TypeResolver.Add(genericInstanceType);
|
||||||
}
|
}
|
||||||
baseTypes.Push(baseType);
|
baseTypes.Push(lastBaseType);
|
||||||
baseType = baseType.Resolve().BaseType;
|
lastBaseType = lastBaseType.Resolve().BaseType;
|
||||||
}
|
}
|
||||||
while (baseTypes.Count > 0)
|
while (baseTypes.Count > 0)
|
||||||
{
|
{
|
||||||
TypeReference typeReference = baseTypes.Pop();
|
var typeReference = baseTypes.Pop();
|
||||||
TypeDefinition typeDefinition = typeReference.Resolve();
|
var typeDefinition = typeReference.Resolve();
|
||||||
foreach (var fieldDefinition in typeDefinition.Fields.Where(WillUnitySerialize))
|
foreach (var fieldDefinition in typeDefinition.Fields.Where(WillUnitySerialize))
|
||||||
{
|
{
|
||||||
if (!IsHiddenByParentClass(baseTypes, fieldDefinition, TypeDef))
|
if (!IsHiddenByParentClass(baseTypes, fieldDefinition, TypeDef))
|
||||||
@ -50,15 +50,15 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var genericInstanceType2 = typeReference as GenericInstanceType;
|
var genericInstanceType = typeReference as GenericInstanceType;
|
||||||
if (genericInstanceType2 != null)
|
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;
|
return nodes;
|
||||||
@ -66,75 +66,60 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private bool WillUnitySerialize(FieldDefinition fieldDefinition)
|
private bool WillUnitySerialize(FieldDefinition fieldDefinition)
|
||||||
{
|
{
|
||||||
bool result;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TypeReference typeReference = TypeResolver.Resolve(fieldDefinition.FieldType);
|
var resolvedFieldType = TypeResolver.Resolve(fieldDefinition.FieldType);
|
||||||
if (UnitySerializationLogic.ShouldNotTryToResolve(typeReference))
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new Exception(string.Format("Exception while processing {0} {1}, error {2}", fieldDefinition.FieldType.FullName, fieldDefinition.FullName, ex.Message));
|
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<TypeReference> parentTypes, FieldDefinition fieldDefinition, TypeDefinition processingType)
|
private static bool IsHiddenByParentClass(IEnumerable<TypeReference> 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<FieldDefinition> FilteredFields()
|
private IEnumerable<FieldDefinition> FilteredFields()
|
||||||
{
|
{
|
||||||
foreach (var f in TypeDef.Fields.Where(WillUnitySerialize))
|
return TypeDef.Fields.Where(WillUnitySerialize).Where(f =>
|
||||||
{
|
UnitySerializationLogic.IsSupportedCollection(f.FieldType) ||
|
||||||
if (UnitySerializationLogic.IsSupportedCollection(f.FieldType) || !f.FieldType.IsGenericInstance || UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve()))
|
!f.FieldType.IsGenericInstance ||
|
||||||
{
|
UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve()));
|
||||||
yield return f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FieldReference ResolveGenericFieldReference(FieldReference fieldRef)
|
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);
|
return TypeDef.Module.ImportReference(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeReference ResolveDeclaringType(TypeReference declaringType)
|
private TypeReference ResolveDeclaringType(TypeReference declaringType)
|
||||||
{
|
{
|
||||||
TypeDefinition typeDefinition = declaringType.Resolve();
|
var typeDefinition = declaringType.Resolve();
|
||||||
TypeReference result;
|
|
||||||
if (typeDefinition == null || !typeDefinition.HasGenericParameters)
|
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);
|
genericInstanceType.GenericArguments.Add(genericParameter);
|
||||||
foreach (GenericParameter item in typeDefinition.GenericParameters)
|
|
||||||
{
|
|
||||||
genericInstanceType.GenericArguments.Add(item);
|
|
||||||
}
|
}
|
||||||
result = TypeResolver.Resolve(genericInstanceType);
|
return TypeResolver.Resolve(genericInstanceType);
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TypeTreeNode> ProcessingFieldRef(FieldReference fieldDef)
|
private List<TypeTreeNode> ProcessingFieldRef(FieldReference fieldDef)
|
||||||
@ -155,7 +140,6 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private static bool RequiresAlignment(TypeReference typeRef)
|
private static bool RequiresAlignment(TypeReference typeRef)
|
||||||
{
|
{
|
||||||
bool result;
|
|
||||||
switch (typeRef.MetadataType)
|
switch (typeRef.MetadataType)
|
||||||
{
|
{
|
||||||
case MetadataType.Boolean:
|
case MetadataType.Boolean:
|
||||||
@ -164,13 +148,10 @@ namespace AssetStudio
|
|||||||
case MetadataType.Byte:
|
case MetadataType.Byte:
|
||||||
case MetadataType.Int16:
|
case MetadataType.Int16:
|
||||||
case MetadataType.UInt16:
|
case MetadataType.UInt16:
|
||||||
result = true;
|
return true;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
result = (UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef)));
|
return UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsSystemString(TypeReference typeRef)
|
private static bool IsSystemString(TypeReference typeRef)
|
||||||
|
65
AssetStudioUtility/Unity.CecilTools/CecilUtils.cs
Normal file
65
AssetStudioUtility/Unity.CecilTools/CecilUtils.cs
Normal file
@ -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<TypeDefinition> AllInterfacesImplementedBy(TypeDefinition typeDefinition)
|
||||||
|
{
|
||||||
|
return TypeAndBaseTypesOf(typeDefinition).SelectMany(t => t.Interfaces).Select(i => i.InterfaceType.CheckedResolve()).Distinct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TypeDefinition> TypeAndBaseTypesOf(TypeReference typeReference)
|
||||||
|
{
|
||||||
|
while (typeReference != null)
|
||||||
|
{
|
||||||
|
var typeDefinition = typeReference.CheckedResolve();
|
||||||
|
yield return typeDefinition;
|
||||||
|
typeReference = typeDefinition.BaseType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<TypeDefinition> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
AssetStudioUtility/Unity.CecilTools/ElementType.cs
Normal file
21
AssetStudioUtility/Unity.CecilTools/ElementType.cs
Normal file
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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, TDefinition>(TReference reference, Func<TReference, TDefinition> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<string> TypesThatShouldHaveHadSerializableAttribute = new HashSet<string>
|
||||||
|
{
|
||||||
|
"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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<string, GenericInstanceHolder> _context = new Dictionary<string, GenericInstanceHolder>();
|
||||||
|
|
||||||
|
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<KeyValuePair<FieldDefinition, TypeResolver>> 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>(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<TypeReference> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
AssetStudioUtility/packages.config
Normal file
4
AssetStudioUtility/packages.config
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Mono.Cecil" version="0.11.3" targetFramework="net472" />
|
||||||
|
</packages>
|
Loading…
Reference in New Issue
Block a user