Update Project
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f7a08e3d1279e542954d80ff88dcd95
|
||||
folderAsset: yes
|
||||
timeCreated: 1537245053
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,382 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ModestTree;
|
||||
using Zenject.ReflectionBaking.Mono.Cecil;
|
||||
using Zenject.ReflectionBaking.Mono.Collections.Generic;
|
||||
using ICustomAttributeProvider = Zenject.ReflectionBaking.Mono.Cecil.ICustomAttributeProvider;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public static class CecilExtensions
|
||||
{
|
||||
public static Type TryGetActualType(this TypeReference typeRef, Assembly assembly)
|
||||
{
|
||||
var reflectionName = GetReflectionName(typeRef);
|
||||
return assembly.GetType(reflectionName);
|
||||
}
|
||||
|
||||
static string GetReflectionName(TypeReference type)
|
||||
{
|
||||
if (type.IsGenericInstance)
|
||||
{
|
||||
var genericInstance = (GenericInstanceType)type;
|
||||
|
||||
return string.Format(
|
||||
"{0}.{1}[{2}]", genericInstance.Namespace, type.Name,
|
||||
String.Join(",", genericInstance.GenericArguments.Select(p => GetReflectionName(p)).ToArray()));
|
||||
}
|
||||
|
||||
return type.FullName;
|
||||
}
|
||||
|
||||
public static List<TypeDefinition> LookupAllTypes(this ModuleDefinition module)
|
||||
{
|
||||
var allTypes = new List<TypeDefinition>();
|
||||
|
||||
foreach (var type in module.Types)
|
||||
{
|
||||
LookupAllTypesInternal(type, allTypes);
|
||||
}
|
||||
|
||||
return allTypes;
|
||||
}
|
||||
|
||||
static void LookupAllTypesInternal(TypeDefinition type, List<TypeDefinition> buffer)
|
||||
{
|
||||
buffer.Add(type);
|
||||
|
||||
foreach (var nestedType in type.NestedTypes)
|
||||
{
|
||||
LookupAllTypesInternal(nestedType, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeReference ImportType<T>(this ModuleDefinition module)
|
||||
{
|
||||
return module.ImportType(typeof(T));
|
||||
}
|
||||
|
||||
public static TypeReference ImportType(this ModuleDefinition module, Type type)
|
||||
{
|
||||
return module.Import(type);
|
||||
}
|
||||
|
||||
public static MethodReference ImportMethod<T>(this ModuleDefinition module, string methodName)
|
||||
{
|
||||
return module.ImportMethod(typeof(T), methodName);
|
||||
}
|
||||
|
||||
public static MethodReference ImportMethod(
|
||||
this ModuleDefinition module, Type type, string methodName)
|
||||
{
|
||||
return module.Import(
|
||||
module.ImportType(type).Resolve().GetMethod(methodName));
|
||||
}
|
||||
|
||||
public static MethodReference ImportMethod<T>(
|
||||
this ModuleDefinition module, string methodName, int numArgs)
|
||||
{
|
||||
return module.ImportMethod(typeof(T), methodName, numArgs);
|
||||
}
|
||||
|
||||
public static MethodReference ImportMethod(
|
||||
this ModuleDefinition module, Type type, string methodName, int numArgs)
|
||||
{
|
||||
return module.Import(
|
||||
module.ImportType(type).Resolve().GetMethod(methodName, numArgs));
|
||||
}
|
||||
|
||||
public static MethodDefinition GetMethod(this TypeDefinition instance, string name)
|
||||
{
|
||||
for (int i = 0; i < instance.Methods.Count; i++)
|
||||
{
|
||||
MethodDefinition methodDef = instance.Methods[i];
|
||||
|
||||
if (string.CompareOrdinal(methodDef.Name, name) == 0)
|
||||
{
|
||||
return methodDef;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MethodDefinition GetMethod(this TypeDefinition instance, string name, params Type[] parameterTypes)
|
||||
{
|
||||
for (int i = 0; i < instance.Methods.Count; i++)
|
||||
{
|
||||
MethodDefinition methodDefinition = instance.Methods[i];
|
||||
|
||||
if (!string.Equals(methodDefinition.Name, name, StringComparison.Ordinal) ||
|
||||
parameterTypes.Length != methodDefinition.Parameters.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodDefinition result = methodDefinition;
|
||||
for (int x = methodDefinition.Parameters.Count - 1; x >= 0; x--)
|
||||
{
|
||||
ParameterDefinition parameter = methodDefinition.Parameters[x];
|
||||
if (!string.Equals(parameter.ParameterType.Name, parameterTypes[x].Name, StringComparison.Ordinal))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MethodDefinition GetMethod(this TypeDefinition instance, string name, params TypeReference[] parameterTypes)
|
||||
{
|
||||
if (instance.Methods != null)
|
||||
{
|
||||
for (int i = 0; i < instance.Methods.Count; i++)
|
||||
{
|
||||
MethodDefinition methodDefinition = instance.Methods[i];
|
||||
if (string.Equals(methodDefinition.Name, name, StringComparison.Ordinal) // Names Match
|
||||
&& parameterTypes.Length == methodDefinition.Parameters.Count) // The same number of parameters
|
||||
{
|
||||
MethodDefinition result = methodDefinition;
|
||||
for (int x = methodDefinition.Parameters.Count - 1; x >= 0; x--)
|
||||
{
|
||||
ParameterDefinition parameter = methodDefinition.Parameters[x];
|
||||
if (!string.Equals(parameter.ParameterType.Name, parameterTypes[x].Name, StringComparison.Ordinal))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MethodDefinition GetMethod(this TypeDefinition instance, string name, int argCount)
|
||||
{
|
||||
for (int i = 0; i < instance.Methods.Count; i++)
|
||||
{
|
||||
MethodDefinition methodDef = instance.Methods[i];
|
||||
|
||||
if (string.CompareOrdinal(methodDef.Name, name) == 0 && methodDef.Parameters.Count == argCount)
|
||||
{
|
||||
return methodDef;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PropertyDefinition GetPropertyDefinition(this TypeDefinition instance, string name)
|
||||
{
|
||||
for (int i = 0; i < instance.Properties.Count; i++)
|
||||
{
|
||||
PropertyDefinition preopertyDef = instance.Properties[i];
|
||||
|
||||
// Properties can only have one argument or they are an indexer.
|
||||
if (string.CompareOrdinal(preopertyDef.Name, name) == 0 && preopertyDef.Parameters.Count == 0)
|
||||
{
|
||||
return preopertyDef;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool HasCustomAttribute<T>(this ICustomAttributeProvider instance)
|
||||
{
|
||||
if (!instance.HasCustomAttributes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Collection<CustomAttribute> attributes = instance.CustomAttributes;
|
||||
|
||||
for(int i = 0; i < attributes.Count; i++)
|
||||
{
|
||||
if (attributes[i].AttributeType.FullName.Equals(typeof(T).FullName, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static MethodReference ChangeDeclaringType(
|
||||
this MethodReference methodDef, TypeReference typeRef)
|
||||
{
|
||||
var newMethodRef = new MethodReference(
|
||||
methodDef.Name, methodDef.ReturnType, typeRef);
|
||||
|
||||
newMethodRef.HasThis = methodDef.HasThis;
|
||||
|
||||
foreach (var arg in methodDef.Parameters)
|
||||
{
|
||||
var paramDef = new ParameterDefinition(arg.ParameterType);
|
||||
|
||||
newMethodRef.Parameters.Add(paramDef);
|
||||
}
|
||||
|
||||
return newMethodRef;
|
||||
}
|
||||
|
||||
public static FieldReference ChangeDeclaringType(
|
||||
this FieldReference fieldDef, TypeReference typeRef)
|
||||
{
|
||||
return new FieldReference(
|
||||
fieldDef.Name, fieldDef.FieldType, typeRef);
|
||||
}
|
||||
|
||||
public static CustomAttribute GetCustomAttribute<T>(this ICustomAttributeProvider instance)
|
||||
{
|
||||
if (!instance.HasCustomAttributes)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<CustomAttribute> attributes = instance.CustomAttributes;
|
||||
|
||||
for (int i = 0; i < attributes.Count; i++)
|
||||
{
|
||||
if (attributes[i].AttributeType.FullName.Equals(typeof(T).FullName, StringComparison.Ordinal))
|
||||
{
|
||||
return attributes[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IEnumerable<TypeReference> GetSpecificBaseTypesAndSelf(
|
||||
this TypeReference specificTypeRef)
|
||||
{
|
||||
yield return specificTypeRef;
|
||||
|
||||
foreach (var ancestor in specificTypeRef.GetSpecificBaseTypesAndSelf())
|
||||
{
|
||||
yield return ancestor;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TypeReference> GetSpecificBaseTypes(
|
||||
this TypeReference specificTypeRef)
|
||||
{
|
||||
var specificBaseTypeRef = specificTypeRef.TryGetSpecificBaseType();
|
||||
|
||||
if (specificBaseTypeRef != null)
|
||||
{
|
||||
yield return specificBaseTypeRef;
|
||||
|
||||
foreach (var ancestor in GetSpecificBaseTypes(specificBaseTypeRef))
|
||||
{
|
||||
yield return ancestor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TypeReference> AllNestParentsAndSelf(this TypeReference specificTypeRef)
|
||||
{
|
||||
yield return specificTypeRef;
|
||||
|
||||
foreach (var ancestor in specificTypeRef.AllNestParents())
|
||||
{
|
||||
yield return ancestor;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TypeReference> AllNestParents(this TypeReference specificTypeRef)
|
||||
{
|
||||
if (specificTypeRef.DeclaringType != null)
|
||||
{
|
||||
yield return specificTypeRef.DeclaringType;
|
||||
|
||||
foreach (var ancestor in specificTypeRef.DeclaringType.AllNestParents())
|
||||
{
|
||||
yield return ancestor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeReference TryResolve(this TypeReference typeRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
return typeRef.Resolve();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeReference TryGetSpecificBaseType(this TypeReference specificTypeRef)
|
||||
{
|
||||
var typeDef = specificTypeRef.Resolve();
|
||||
|
||||
if (typeDef.BaseType == null
|
||||
|| typeDef.BaseType.FullName == "System.Object")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var specificBaseTypeRef = typeDef.BaseType;
|
||||
|
||||
if (specificBaseTypeRef.ContainsGenericParameter)
|
||||
{
|
||||
var genericArgMap = new Dictionary<string, TypeReference>();
|
||||
|
||||
foreach (var ancestor in specificTypeRef.AllNestParentsAndSelf())
|
||||
{
|
||||
var specificTypeRefGenericInstance = ancestor as GenericInstanceType;
|
||||
|
||||
if (specificTypeRefGenericInstance != null)
|
||||
{
|
||||
for (int i = 0; i < typeDef.GenericParameters.Count; i++)
|
||||
{
|
||||
genericArgMap[typeDef.GenericParameters[i].Name] = specificTypeRefGenericInstance.GenericArguments[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
specificBaseTypeRef = FillInGenericParameters(specificBaseTypeRef, genericArgMap);
|
||||
}
|
||||
|
||||
return specificBaseTypeRef;
|
||||
}
|
||||
|
||||
public static TypeReference FillInGenericParameters(
|
||||
TypeReference type, Dictionary<string, TypeReference> genericArgMap)
|
||||
{
|
||||
var genericType = type as GenericInstanceType;
|
||||
Assert.IsNotNull(genericType);
|
||||
|
||||
var genericTypeClone = new GenericInstanceType(type.Resolve());
|
||||
|
||||
for (int i = 0; i < genericType.GenericArguments.Count; i++)
|
||||
{
|
||||
var arg = genericType.GenericArguments[i];
|
||||
|
||||
if (arg.IsGenericParameter)
|
||||
{
|
||||
Assert.That(genericArgMap.ContainsKey(arg.Name), "Could not find key '{0}' for type '{1}'", arg.Name, type.FullName);
|
||||
|
||||
genericTypeClone.GenericArguments.Add(genericArgMap[arg.Name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
genericTypeClone.GenericArguments.Add(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return genericTypeClone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89602ba5a473d064387392d8d2055aa4
|
||||
timeCreated: 1537234617
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+752
@@ -0,0 +1,752 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using ModestTree;
|
||||
using Zenject.Internal;
|
||||
using Zenject.ReflectionBaking.Mono.Cecil;
|
||||
using Zenject.ReflectionBaking.Mono.Cecil.Cil;
|
||||
using Zenject.ReflectionBaking.Mono.Collections.Generic;
|
||||
using MethodAttributes = Zenject.ReflectionBaking.Mono.Cecil.MethodAttributes;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public class ReflectionBakingModuleEditor
|
||||
{
|
||||
readonly Assembly _assembly;
|
||||
readonly ModuleDefinition _module;
|
||||
readonly List<Regex> _namespaceRegexes;
|
||||
|
||||
MethodReference _zenjectTypeInfoConstructor;
|
||||
MethodReference _injectableInfoConstructor;
|
||||
MethodReference _injectMethodInfoConstructor;
|
||||
MethodReference _injectMemberInfoConstructor;
|
||||
MethodReference _constructorInfoConstructor;
|
||||
MethodReference _getTypeFromHandleMethod;
|
||||
MethodReference _funcConstructor;
|
||||
MethodReference _funcPostInject;
|
||||
MethodReference _funcMemberSetter;
|
||||
MethodReference _preserveConstructor;
|
||||
|
||||
TypeReference _injectMethodInfoType;
|
||||
TypeReference _injectMemberInfoType;
|
||||
TypeReference _injectableInfoType;
|
||||
TypeReference _objectArrayType;
|
||||
TypeReference _zenjectTypeInfoType;
|
||||
|
||||
ReflectionBakingModuleEditor(
|
||||
ModuleDefinition module, Assembly assembly, List<string> namespacePatterns)
|
||||
{
|
||||
_module = module;
|
||||
_assembly = assembly;
|
||||
_namespaceRegexes = namespacePatterns.Select(CreateRegex).ToList();
|
||||
_namespaceRegexes.Add(CreateRegex("^Zenject"));
|
||||
}
|
||||
|
||||
public static int WeaveAssembly(
|
||||
ModuleDefinition module, Assembly assembly)
|
||||
{
|
||||
return WeaveAssembly(module, assembly, new List<string>());
|
||||
}
|
||||
|
||||
public static int WeaveAssembly(
|
||||
ModuleDefinition module, Assembly assembly, List<string> namespacePatterns)
|
||||
{
|
||||
return new ReflectionBakingModuleEditor(module, assembly, namespacePatterns).Run();
|
||||
}
|
||||
|
||||
int Run()
|
||||
{
|
||||
SaveImports();
|
||||
|
||||
int numTypesEditted = 0;
|
||||
|
||||
var allTypes = _module.LookupAllTypes();
|
||||
|
||||
foreach (var typeDef in allTypes)
|
||||
{
|
||||
if (_namespaceRegexes.Any() && !_namespaceRegexes.Any(x => x.IsMatch(typeDef.FullName)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var actualType = typeDef.TryGetActualType(_assembly);
|
||||
|
||||
if (actualType == null)
|
||||
{
|
||||
Log.Warn("Could not find actual type for type '{0}', skipping", typeDef.FullName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryEditType(typeDef, actualType))
|
||||
{
|
||||
numTypesEditted++;
|
||||
}
|
||||
}
|
||||
|
||||
return numTypesEditted;
|
||||
}
|
||||
|
||||
Regex CreateRegex(string regexStr)
|
||||
{
|
||||
return new Regex(regexStr, RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
void SaveImports()
|
||||
{
|
||||
_zenjectTypeInfoType = _module.ImportType<InjectTypeInfo>();
|
||||
_zenjectTypeInfoConstructor = _module.ImportMethod<InjectTypeInfo>(".ctor");
|
||||
|
||||
_injectableInfoConstructor = _module.ImportMethod<InjectableInfo>(".ctor");
|
||||
|
||||
_getTypeFromHandleMethod = _module.ImportMethod<Type>("GetTypeFromHandle", 1);
|
||||
|
||||
_injectMethodInfoType = _module.ImportType<InjectTypeInfo.InjectMethodInfo>();
|
||||
_injectMethodInfoConstructor = _module.ImportMethod<InjectTypeInfo.InjectMethodInfo>(".ctor");
|
||||
|
||||
_injectMemberInfoType = _module.ImportType<InjectTypeInfo.InjectMemberInfo>();
|
||||
_injectMemberInfoConstructor = _module.ImportMethod<InjectTypeInfo.InjectMemberInfo>(".ctor");
|
||||
|
||||
_preserveConstructor = _module.ImportMethod<Zenject.Internal.PreserveAttribute>(".ctor");
|
||||
_constructorInfoConstructor = _module.ImportMethod<InjectTypeInfo.InjectConstructorInfo>(".ctor");
|
||||
|
||||
_injectableInfoType = _module.ImportType<InjectableInfo>();
|
||||
|
||||
_objectArrayType = _module.Import(typeof(object[]));
|
||||
|
||||
_funcConstructor = _module.ImportMethod<ZenFactoryMethod>(".ctor", 2);
|
||||
|
||||
_funcPostInject = _module.ImportMethod<ZenInjectMethod>(".ctor", 2);
|
||||
|
||||
_funcMemberSetter = _module.ImportMethod<ZenMemberSetterMethod>(".ctor", 2);
|
||||
}
|
||||
|
||||
public bool TryEditType(TypeDefinition typeDef, Type actualType)
|
||||
{
|
||||
if (actualType.IsEnum || actualType.IsValueType || actualType.IsInterface
|
||||
|| actualType.HasAttribute<NoReflectionBakingAttribute>()
|
||||
|| IsStaticClass(actualType) || actualType.DerivesFromOrEqual<Delegate>() || actualType.DerivesFromOrEqual<Attribute>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow running on the same dll multiple times without causing problems
|
||||
if (IsTypeProcessed(typeDef))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var typeInfo = ReflectionTypeAnalyzer.GetReflectionInfo(actualType);
|
||||
|
||||
var factoryMethod = TryAddFactoryMethod(typeDef, typeInfo);
|
||||
var genericTypeDef = CreateGenericInstanceWithParameters(typeDef);
|
||||
var fieldSetMethods = AddFieldSetters(typeDef, genericTypeDef, typeInfo);
|
||||
var propertySetMethods = AddPropertySetters(typeDef, genericTypeDef, typeInfo);
|
||||
var postInjectMethods = AddPostInjectMethods(typeDef, genericTypeDef, typeInfo);
|
||||
|
||||
CreateGetInfoMethod(
|
||||
typeDef, genericTypeDef, typeInfo,
|
||||
factoryMethod, fieldSetMethods, propertySetMethods, postInjectMethods);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.ErrorException("Error when modifying type '{0}'".Fmt(actualType), e);
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsStaticClass(Type type)
|
||||
{
|
||||
// Apparently this is unique to static classes
|
||||
return type.IsAbstract && type.IsSealed;
|
||||
}
|
||||
|
||||
// We are already processed if our static constructor calls TypeAnalyzer
|
||||
bool IsTypeProcessed(TypeDefinition typeDef)
|
||||
{
|
||||
return typeDef.GetMethod(TypeAnalyzer.ReflectionBakingGetInjectInfoMethodName) != null;
|
||||
}
|
||||
|
||||
void EmitCastOperation(ILProcessor processor, Type type, Collection<GenericParameter> genericParams)
|
||||
{
|
||||
if (type.IsGenericParameter)
|
||||
{
|
||||
processor.Emit(OpCodes.Unbox_Any, genericParams[type.GenericParameterPosition]);
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
processor.Emit(OpCodes.Unbox_Any, _module.TypeSystem.Int32);
|
||||
}
|
||||
else if (type.IsValueType)
|
||||
{
|
||||
processor.Emit(OpCodes.Unbox_Any, _module.ImportType(type));
|
||||
}
|
||||
else
|
||||
{
|
||||
processor.Emit(OpCodes.Castclass, CreateGenericInstanceIfNecessary(type, genericParams));
|
||||
}
|
||||
}
|
||||
|
||||
TypeReference CreateGenericInstanceWithParameters(TypeDefinition typeDef)
|
||||
{
|
||||
if (typeDef.GenericParameters.Any())
|
||||
{
|
||||
var genericInstance = new GenericInstanceType(typeDef);
|
||||
|
||||
foreach (var parameter in typeDef.GenericParameters)
|
||||
{
|
||||
genericInstance.GenericArguments.Add(parameter);
|
||||
}
|
||||
|
||||
return genericInstance;
|
||||
}
|
||||
|
||||
return typeDef;
|
||||
}
|
||||
|
||||
MethodDefinition TryAddFactoryMethod(
|
||||
TypeDefinition typeDef, ReflectionTypeInfo typeInfo)
|
||||
{
|
||||
if (typeInfo.Type.GetParentTypes().Any(x => x.FullName == "UnityEngine.Component"))
|
||||
{
|
||||
Assert.That(typeInfo.InjectConstructor.Parameters.IsEmpty());
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeInfo.InjectConstructor.ConstructorInfo == null)
|
||||
{
|
||||
// static classes, abstract types
|
||||
return null;
|
||||
}
|
||||
|
||||
var factoryMethod = new MethodDefinition(
|
||||
TypeAnalyzer.ReflectionBakingFactoryMethodName,
|
||||
MethodAttributes.Private | MethodAttributes.HideBySig |
|
||||
MethodAttributes.Static,
|
||||
_module.TypeSystem.Object);
|
||||
|
||||
var p1 = new ParameterDefinition(_objectArrayType);
|
||||
p1.Name = "P_0";
|
||||
factoryMethod.Parameters.Add(p1);
|
||||
|
||||
var body = factoryMethod.Body;
|
||||
body.InitLocals = true;
|
||||
|
||||
var processor = body.GetILProcessor();
|
||||
|
||||
var returnValueVar = new VariableDefinition(_module.TypeSystem.Object);
|
||||
body.Variables.Add(returnValueVar);
|
||||
|
||||
processor.Emit(OpCodes.Nop);
|
||||
|
||||
Assert.IsNotNull(typeInfo.InjectConstructor);
|
||||
|
||||
var args = typeInfo.InjectConstructor.Parameters;
|
||||
|
||||
for (int i = 0; i < args.Count; i++)
|
||||
{
|
||||
var arg = args[i];
|
||||
|
||||
processor.Emit(OpCodes.Ldarg_0);
|
||||
processor.Emit(OpCodes.Ldc_I4, i);
|
||||
processor.Emit(OpCodes.Ldelem_Ref);
|
||||
|
||||
EmitCastOperation(
|
||||
processor, arg.ParameterInfo.ParameterType, typeDef.GenericParameters);
|
||||
}
|
||||
|
||||
processor.Emit(OpCodes.Newobj, _module.Import(typeInfo.InjectConstructor.ConstructorInfo));
|
||||
|
||||
processor.Emit(OpCodes.Stloc_0);
|
||||
processor.Emit(OpCodes.Ldloc_S, returnValueVar);
|
||||
processor.Emit(OpCodes.Ret);
|
||||
|
||||
typeDef.Methods.Add(factoryMethod);
|
||||
|
||||
return factoryMethod;
|
||||
}
|
||||
|
||||
void AddPostInjectMethodBody(
|
||||
ILProcessor processor, ReflectionTypeInfo.InjectMethodInfo postInjectInfo, TypeDefinition typeDef, TypeReference genericTypeDef)
|
||||
{
|
||||
processor.Emit(OpCodes.Nop);
|
||||
|
||||
TypeReference declaringTypeDef;
|
||||
MethodReference actualMethodDef;
|
||||
|
||||
if (!TryFindLocalMethod(
|
||||
genericTypeDef, postInjectInfo.MethodInfo.Name, out declaringTypeDef, out actualMethodDef))
|
||||
{
|
||||
throw Assert.CreateException();
|
||||
}
|
||||
|
||||
processor.Emit(OpCodes.Ldarg_0);
|
||||
processor.Emit(OpCodes.Castclass, declaringTypeDef);
|
||||
|
||||
for (int k = 0; k < postInjectInfo.Parameters.Count; k++)
|
||||
{
|
||||
var injectInfo = postInjectInfo.Parameters[k];
|
||||
|
||||
processor.Emit(OpCodes.Ldarg_1);
|
||||
processor.Emit(OpCodes.Ldc_I4, k);
|
||||
processor.Emit(OpCodes.Ldelem_Ref);
|
||||
|
||||
EmitCastOperation(processor, injectInfo.ParameterInfo.ParameterType, typeDef.GenericParameters);
|
||||
}
|
||||
|
||||
processor.Emit(OpCodes.Callvirt, actualMethodDef);
|
||||
processor.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
MethodDefinition AddPostInjectMethod(
|
||||
string name, ReflectionTypeInfo.InjectMethodInfo postInjectInfo, TypeDefinition typeDef, TypeReference genericTypeDef)
|
||||
{
|
||||
var methodDef = new MethodDefinition(
|
||||
name,
|
||||
MethodAttributes.Private | MethodAttributes.HideBySig |
|
||||
MethodAttributes.Static,
|
||||
_module.TypeSystem.Void);
|
||||
|
||||
var p1 = new ParameterDefinition(_module.TypeSystem.Object);
|
||||
p1.Name = "P_0";
|
||||
methodDef.Parameters.Add(p1);
|
||||
|
||||
var p2 = new ParameterDefinition(_objectArrayType);
|
||||
p2.Name = "P_1";
|
||||
methodDef.Parameters.Add(p2);
|
||||
|
||||
var body = methodDef.Body;
|
||||
var processor = body.GetILProcessor();
|
||||
|
||||
AddPostInjectMethodBody(processor, postInjectInfo, typeDef, genericTypeDef);
|
||||
|
||||
typeDef.Methods.Add(methodDef);
|
||||
|
||||
return methodDef;
|
||||
}
|
||||
|
||||
List<MethodDefinition> AddPostInjectMethods(
|
||||
TypeDefinition typeDef, TypeReference genericTypeDef, ReflectionTypeInfo typeInfo)
|
||||
{
|
||||
var postInjectMethods = new List<MethodDefinition>();
|
||||
|
||||
for (int i = 0; i < typeInfo.InjectMethods.Count; i++)
|
||||
{
|
||||
postInjectMethods.Add(
|
||||
AddPostInjectMethod(
|
||||
TypeAnalyzer.ReflectionBakingInjectMethodPrefix + i, typeInfo.InjectMethods[i], typeDef, genericTypeDef));
|
||||
}
|
||||
|
||||
return postInjectMethods;
|
||||
}
|
||||
|
||||
void EmitSetterMethod(
|
||||
ILProcessor processor, MemberInfo memberInfo, TypeDefinition typeDef, TypeReference genericTypeDef)
|
||||
{
|
||||
processor.Emit(OpCodes.Nop);
|
||||
|
||||
processor.Emit(OpCodes.Ldarg_0);
|
||||
processor.Emit(OpCodes.Castclass, genericTypeDef);
|
||||
|
||||
processor.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
if (memberInfo is FieldInfo)
|
||||
{
|
||||
var fieldInfo = (FieldInfo)memberInfo;
|
||||
|
||||
EmitCastOperation(processor, fieldInfo.FieldType, typeDef.GenericParameters);
|
||||
|
||||
processor.Emit(OpCodes.Stfld, FindLocalField(genericTypeDef, fieldInfo.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
var propertyInfo = (PropertyInfo)memberInfo;
|
||||
|
||||
EmitCastOperation(processor, propertyInfo.PropertyType, typeDef.GenericParameters);
|
||||
|
||||
processor.Emit(OpCodes.Callvirt, FindLocalPropertySetMethod(genericTypeDef, propertyInfo.Name));
|
||||
}
|
||||
|
||||
processor.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
MethodDefinition AddSetterMethod(
|
||||
string name, MemberInfo memberInfo, TypeDefinition typeDef, TypeReference genericTypeDef)
|
||||
{
|
||||
var methodDef = new MethodDefinition(
|
||||
name,
|
||||
MethodAttributes.Private | MethodAttributes.HideBySig |
|
||||
MethodAttributes.Static,
|
||||
_module.TypeSystem.Void);
|
||||
|
||||
var p1 = new ParameterDefinition(_module.TypeSystem.Object);
|
||||
p1.Name = "P_0";
|
||||
methodDef.Parameters.Add(p1);
|
||||
|
||||
var p2 = new ParameterDefinition(_module.TypeSystem.Object);
|
||||
p2.Name = "P_1";
|
||||
methodDef.Parameters.Add(p2);
|
||||
|
||||
methodDef.Body.InitLocals = true;
|
||||
|
||||
EmitSetterMethod(
|
||||
methodDef.Body.GetILProcessor(), memberInfo, typeDef, genericTypeDef);
|
||||
|
||||
typeDef.Methods.Add(methodDef);
|
||||
|
||||
return methodDef;
|
||||
}
|
||||
|
||||
List<MethodDefinition> AddPropertySetters(
|
||||
TypeDefinition typeDef, TypeReference genericTypeDef, ReflectionTypeInfo typeInfo)
|
||||
{
|
||||
var methodDefs = new List<MethodDefinition>();
|
||||
|
||||
for (int i = 0; i < typeInfo.InjectProperties.Count; i++)
|
||||
{
|
||||
methodDefs.Add(
|
||||
AddSetterMethod(
|
||||
TypeAnalyzer.ReflectionBakingPropertySetterPrefix + i,
|
||||
typeInfo.InjectProperties[i].PropertyInfo, typeDef, genericTypeDef));
|
||||
}
|
||||
|
||||
return methodDefs;
|
||||
}
|
||||
|
||||
List<MethodDefinition> AddFieldSetters(
|
||||
TypeDefinition typeDef, TypeReference genericTypeDef, ReflectionTypeInfo typeInfo)
|
||||
{
|
||||
var methodDefs = new List<MethodDefinition>();
|
||||
|
||||
for (int i = 0; i < typeInfo.InjectFields.Count; i++)
|
||||
{
|
||||
methodDefs.Add(
|
||||
AddSetterMethod(
|
||||
TypeAnalyzer.ReflectionBakingFieldSetterPrefix + i,
|
||||
typeInfo.InjectFields[i].FieldInfo, typeDef, genericTypeDef));
|
||||
}
|
||||
|
||||
return methodDefs;
|
||||
}
|
||||
|
||||
void CreateGetInfoMethod(
|
||||
TypeDefinition typeDef, TypeReference genericTypeDef, ReflectionTypeInfo typeInfo,
|
||||
MethodDefinition factoryMethod, List<MethodDefinition> fieldSetMethods,
|
||||
List<MethodDefinition> propertySetMethods, List<MethodDefinition> postInjectMethods)
|
||||
{
|
||||
var getInfoMethodDef = new MethodDefinition(
|
||||
TypeAnalyzer.ReflectionBakingGetInjectInfoMethodName,
|
||||
MethodAttributes.Private | MethodAttributes.HideBySig |
|
||||
MethodAttributes.Static,
|
||||
_zenjectTypeInfoType);
|
||||
|
||||
typeDef.Methods.Add(getInfoMethodDef);
|
||||
|
||||
getInfoMethodDef.CustomAttributes.Add(
|
||||
new CustomAttribute(_preserveConstructor));
|
||||
|
||||
var returnValueVar = new VariableDefinition(_module.TypeSystem.Object);
|
||||
|
||||
var body = getInfoMethodDef.Body;
|
||||
|
||||
body.Variables.Add(returnValueVar);
|
||||
body.InitLocals = true;
|
||||
|
||||
var instructions = new List<Instruction>();
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldtoken, genericTypeDef));
|
||||
instructions.Add(Instruction.Create(OpCodes.Call, _getTypeFromHandleMethod));
|
||||
|
||||
if (factoryMethod == null)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
}
|
||||
else
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldftn, factoryMethod.ChangeDeclaringType(genericTypeDef)));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _funcConstructor));
|
||||
}
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, typeInfo.InjectConstructor.Parameters.Count));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newarr, _injectableInfoType));
|
||||
|
||||
for (int i = 0; i < typeInfo.InjectConstructor.Parameters.Count; i++)
|
||||
{
|
||||
var injectableInfo = typeInfo.InjectConstructor.Parameters[i].InjectableInfo;
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Dup));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i));
|
||||
|
||||
EmitNewInjectableInfoInstructions(
|
||||
instructions, injectableInfo, typeDef);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
|
||||
}
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _constructorInfoConstructor));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, typeInfo.InjectMethods.Count));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newarr, _injectMethodInfoType));
|
||||
|
||||
Assert.IsEqual(postInjectMethods.Count, typeInfo.InjectMethods.Count);
|
||||
|
||||
for (int i = 0; i < typeInfo.InjectMethods.Count; i++)
|
||||
{
|
||||
var injectMethodInfo = typeInfo.InjectMethods[i];
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Dup));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i));
|
||||
|
||||
AddInjectableMethodInstructions(
|
||||
instructions, injectMethodInfo, typeDef, genericTypeDef, postInjectMethods[i]);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
|
||||
}
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, fieldSetMethods.Count + propertySetMethods.Count));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newarr, _injectMemberInfoType));
|
||||
|
||||
for (int i = 0; i < fieldSetMethods.Count; i++)
|
||||
{
|
||||
var injectField = typeInfo.InjectFields[i];
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Dup));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i));
|
||||
|
||||
AddInjectableMemberInstructions(
|
||||
instructions,
|
||||
injectField.InjectableInfo, injectField.FieldInfo.Name,
|
||||
typeDef, genericTypeDef, fieldSetMethods[i]);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
|
||||
}
|
||||
|
||||
for (int i = 0; i < propertySetMethods.Count; i++)
|
||||
{
|
||||
var injectProperty = typeInfo.InjectProperties[i];
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Dup));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, fieldSetMethods.Count + i));
|
||||
|
||||
AddInjectableMemberInstructions(
|
||||
instructions,
|
||||
injectProperty.InjectableInfo,
|
||||
injectProperty.PropertyInfo.Name, typeDef, genericTypeDef,
|
||||
propertySetMethods[i]);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
|
||||
}
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _zenjectTypeInfoConstructor));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Stloc_0));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldloc_S, returnValueVar));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
|
||||
var processor = body.GetILProcessor();
|
||||
|
||||
foreach (var instruction in instructions)
|
||||
{
|
||||
processor.Append(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
MethodReference FindLocalPropertySetMethod(
|
||||
TypeReference specificTypeRef, string memberName)
|
||||
{
|
||||
foreach (var typeRef in specificTypeRef.GetSpecificBaseTypesAndSelf())
|
||||
{
|
||||
var candidatePropertyDef = typeRef.Resolve().Properties
|
||||
.Where(x => x.Name == memberName).SingleOrDefault();
|
||||
|
||||
if (candidatePropertyDef != null)
|
||||
{
|
||||
return candidatePropertyDef.SetMethod.ChangeDeclaringType(typeRef);
|
||||
}
|
||||
}
|
||||
|
||||
throw Assert.CreateException();
|
||||
}
|
||||
|
||||
FieldReference FindLocalField(
|
||||
TypeReference specificTypeRef, string fieldName)
|
||||
{
|
||||
foreach (var typeRef in specificTypeRef.GetSpecificBaseTypesAndSelf())
|
||||
{
|
||||
var candidateFieldDef = typeRef.Resolve().Fields
|
||||
.Where(x => x.Name == fieldName).SingleOrDefault();
|
||||
|
||||
if (candidateFieldDef != null)
|
||||
{
|
||||
return candidateFieldDef.ChangeDeclaringType(typeRef);
|
||||
}
|
||||
}
|
||||
|
||||
throw Assert.CreateException();
|
||||
}
|
||||
|
||||
bool TryFindLocalMethod(
|
||||
TypeReference specificTypeRef, string methodName, out TypeReference declaringTypeRef, out MethodReference methodRef)
|
||||
{
|
||||
foreach (var typeRef in specificTypeRef.GetSpecificBaseTypesAndSelf())
|
||||
{
|
||||
var candidateMethodDef = typeRef.Resolve().Methods
|
||||
.Where(x => x.Name == methodName).SingleOrDefault();
|
||||
|
||||
if (candidateMethodDef != null)
|
||||
{
|
||||
declaringTypeRef = typeRef;
|
||||
methodRef = candidateMethodDef.ChangeDeclaringType(typeRef);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
declaringTypeRef = null;
|
||||
methodRef = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddObjectInstructions(
|
||||
List<Instruction> instructions,
|
||||
object identifier)
|
||||
{
|
||||
if (identifier == null)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
}
|
||||
else if (identifier is string)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldstr, (string)identifier));
|
||||
}
|
||||
else if (identifier is int)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)identifier));
|
||||
instructions.Add(Instruction.Create(OpCodes.Box, _module.Import(typeof(int))));
|
||||
}
|
||||
else if (identifier.GetType().IsEnum)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)identifier));
|
||||
instructions.Add(Instruction.Create(OpCodes.Box, _module.Import(identifier.GetType())));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Assert.CreateException(
|
||||
"Cannot process values with type '{0}' currently. Feel free to add support for this and submit a pull request to github.", identifier.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
TypeReference CreateGenericInstanceIfNecessary(
|
||||
Type memberType, Collection<GenericParameter> genericParams)
|
||||
{
|
||||
if (!memberType.ContainsGenericParameters)
|
||||
{
|
||||
return _module.Import(memberType);
|
||||
}
|
||||
|
||||
if (memberType.IsGenericParameter)
|
||||
{
|
||||
return genericParams[memberType.GenericParameterPosition];
|
||||
}
|
||||
|
||||
if (memberType.IsArray)
|
||||
{
|
||||
return new ArrayType(
|
||||
CreateGenericInstanceIfNecessary(memberType.GetElementType(), genericParams), memberType.GetArrayRank());
|
||||
}
|
||||
|
||||
var genericMemberType = memberType.GetGenericTypeDefinition();
|
||||
|
||||
var genericInstance = new GenericInstanceType(_module.Import(genericMemberType));
|
||||
|
||||
foreach (var arg in memberType.GenericArguments())
|
||||
{
|
||||
genericInstance.GenericArguments.Add(
|
||||
CreateGenericInstanceIfNecessary(arg, genericParams));
|
||||
}
|
||||
|
||||
return genericInstance;
|
||||
}
|
||||
|
||||
void AddInjectableMemberInstructions(
|
||||
List<Instruction> instructions,
|
||||
InjectableInfo injectableInfo, string name,
|
||||
TypeDefinition typeDef, TypeReference genericTypeDef,
|
||||
MethodDefinition methodDef)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldftn, methodDef.ChangeDeclaringType(genericTypeDef)));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _funcMemberSetter));
|
||||
|
||||
EmitNewInjectableInfoInstructions(
|
||||
instructions, injectableInfo, typeDef);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _injectMemberInfoConstructor));
|
||||
}
|
||||
|
||||
void AddInjectableMethodInstructions(
|
||||
List<Instruction> instructions,
|
||||
ReflectionTypeInfo.InjectMethodInfo injectMethod,
|
||||
TypeDefinition typeDef, TypeReference genericTypeDef,
|
||||
MethodDefinition methodDef)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldftn, methodDef.ChangeDeclaringType(genericTypeDef)));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _funcPostInject));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, injectMethod.Parameters.Count));
|
||||
instructions.Add(Instruction.Create(OpCodes.Newarr, _injectableInfoType));
|
||||
|
||||
for (int i = 0; i < injectMethod.Parameters.Count; i++)
|
||||
{
|
||||
var injectableInfo = injectMethod.Parameters[i].InjectableInfo;
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Dup));
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i));
|
||||
|
||||
EmitNewInjectableInfoInstructions(
|
||||
instructions, injectableInfo, typeDef);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
|
||||
}
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldstr, injectMethod.MethodInfo.Name));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _injectMethodInfoConstructor));
|
||||
}
|
||||
|
||||
void EmitNewInjectableInfoInstructions(
|
||||
List<Instruction> instructions,
|
||||
InjectableInfo injectableInfo,
|
||||
TypeDefinition typeDef)
|
||||
{
|
||||
if (injectableInfo.Optional)
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4_1));
|
||||
}
|
||||
else
|
||||
{
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
|
||||
}
|
||||
|
||||
AddObjectInstructions(instructions, injectableInfo.Identifier);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldstr, injectableInfo.MemberName));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldtoken, CreateGenericInstanceIfNecessary(injectableInfo.MemberType, typeDef.GenericParameters)));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Call, _getTypeFromHandleMethod));
|
||||
|
||||
AddObjectInstructions(instructions, injectableInfo.DefaultValue);
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)injectableInfo.SourceType));
|
||||
|
||||
instructions.Add(Instruction.Create(OpCodes.Newobj, _injectableInfoConstructor));
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a664c0011937115449c81d8ca4a2f6c7
|
||||
timeCreated: 1538185954
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3879d05eafe89b844a5fc0db8cfd9c55
|
||||
folderAsset: yes
|
||||
timeCreated: 1537245053
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Binary file not shown.
+32
@@ -0,0 +1,32 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b309800e744d8c46ad868763fc9c429
|
||||
timeCreated: 1538196675
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Binary file not shown.
+32
@@ -0,0 +1,32 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6433e8939bdf284693b7fa9b719bfcd
|
||||
timeCreated: 1538196675
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Binary file not shown.
+32
@@ -0,0 +1,32 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58ca997f0a3dfb84590febf580194214
|
||||
timeCreated: 1538196674
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Binary file not shown.
+32
@@ -0,0 +1,32 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fdc9d5333ed94347bd076c3946dd19d
|
||||
timeCreated: 1538196673
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdf7617b0450e55498cedcfc70529ff5
|
||||
folderAsset: yes
|
||||
timeCreated: 1537245054
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public class AssemblyPathRegistry
|
||||
{
|
||||
static List<string> _assemblies;
|
||||
|
||||
public static List<string> GetAllGeneratedAssemblyRelativePaths()
|
||||
{
|
||||
if (_assemblies == null)
|
||||
{
|
||||
_assemblies = LookupAllGeneratedAssemblyPaths();
|
||||
Assert.IsNotNull(_assemblies);
|
||||
}
|
||||
|
||||
return _assemblies;
|
||||
}
|
||||
|
||||
static bool IsManagedAssembly(string systemPath)
|
||||
{
|
||||
DllType dllType = InternalEditorUtility.DetectDotNetDll(systemPath);
|
||||
return dllType != DllType.Unknown && dllType != DllType.Native;
|
||||
}
|
||||
|
||||
static List<string> LookupAllGeneratedAssemblyPaths()
|
||||
{
|
||||
var assemblies = new List<string>(20);
|
||||
|
||||
// We could also add the ones in the project but we probably don't want to edit those
|
||||
//FindAssemblies(Application.dataPath, 120, assemblies);
|
||||
|
||||
FindAssemblies(Application.dataPath + "/../Library/ScriptAssemblies/", 2, assemblies);
|
||||
|
||||
return assemblies;
|
||||
}
|
||||
|
||||
public static void FindAssemblies(string systemPath, int maxDepth, List<string> result)
|
||||
{
|
||||
if (maxDepth > 0)
|
||||
{
|
||||
if (Directory.Exists(systemPath))
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(systemPath);
|
||||
|
||||
result.AddRange(
|
||||
dirInfo.GetFiles().Select(x => x.FullName)
|
||||
.Where(IsManagedAssembly)
|
||||
.Select(ReflectionBakingInternalUtil.ConvertAbsoluteToAssetPath));
|
||||
|
||||
var directories = dirInfo.GetDirectories();
|
||||
|
||||
for (int i = 0; i < directories.Length; i++)
|
||||
{
|
||||
DirectoryInfo current = directories[i];
|
||||
|
||||
FindAssemblies(current.FullName, maxDepth - 1, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f96372c95411c904bb55ba67b55e0c84
|
||||
timeCreated: 1537003252
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEngine;
|
||||
using Zenject.ReflectionBaking.Mono.Cecil;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public static class ReflectionBakingBuildObserver
|
||||
{
|
||||
[InitializeOnLoadMethod]
|
||||
public static void Initialize()
|
||||
{
|
||||
CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompiled;
|
||||
}
|
||||
|
||||
static void OnAssemblyCompiled(string assemblyAssetPath, CompilerMessage[] messages)
|
||||
{
|
||||
#if !UNITY_2018_1_OR_NEWER
|
||||
if (Application.isEditor && !BuildPipeline.isBuildingPlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WSAPlayer)
|
||||
{
|
||||
Log.Warn("Zenject reflection baking skipped because it is not currently supported on WSA platform!");
|
||||
}
|
||||
else
|
||||
{
|
||||
TryWeaveAssembly(assemblyAssetPath);
|
||||
}
|
||||
}
|
||||
|
||||
static void TryWeaveAssembly(string assemblyAssetPath)
|
||||
{
|
||||
var settings = ReflectionBakingInternalUtil.TryGetEnabledSettingsInstance();
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.AllGeneratedAssemblies && settings.ExcludeAssemblies.Contains(assemblyAssetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!settings.AllGeneratedAssemblies && !settings.IncludeAssemblies.Contains(assemblyAssetPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
|
||||
var assemblyFullPath = ReflectionBakingInternalUtil.ConvertAssetPathToSystemPath(assemblyAssetPath);
|
||||
|
||||
var readerParameters = new ReaderParameters
|
||||
{
|
||||
AssemblyResolver = new UnityAssemblyResolver(),
|
||||
// Is this necessary?
|
||||
//ReadSymbols = true,
|
||||
};
|
||||
|
||||
var module = ModuleDefinition.ReadModule(assemblyFullPath, readerParameters);
|
||||
|
||||
var assemblyRefNames = module.AssemblyReferences.Select(x => x.Name.ToLower()).ToList();
|
||||
|
||||
if (!assemblyRefNames.Contains("zenject-usage"))
|
||||
{
|
||||
// Zenject-usage is used by the generated methods
|
||||
// Important that we do this check otherwise we can corrupt some dlls that don't have access to it
|
||||
return;
|
||||
}
|
||||
|
||||
var assemblyName = Path.GetFileNameWithoutExtension(assemblyAssetPath);
|
||||
var assembly = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.Where(x => x.GetName().Name == assemblyName).OnlyOrDefault();
|
||||
|
||||
Assert.IsNotNull(assembly, "Could not find unique assembly '{0}' in currently loaded list of assemblies", assemblyName);
|
||||
|
||||
int numTypesChanged = ReflectionBakingModuleEditor.WeaveAssembly(
|
||||
module, assembly, settings.NamespacePatterns);
|
||||
|
||||
if (numTypesChanged > 0)
|
||||
{
|
||||
var writerParams = new WriterParameters()
|
||||
{
|
||||
// Is this necessary?
|
||||
//WriteSymbols = true
|
||||
};
|
||||
|
||||
module.Write(assemblyFullPath, writerParams);
|
||||
|
||||
Debug.Log("Added reflection baking to '{0}' types in assembly '{1}', took {2:0.00} seconds"
|
||||
.Fmt(numTypesChanged, Path.GetFileName(assemblyAssetPath), stopwatch.Elapsed.TotalSeconds));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 374dbffd3e3c6504489ada7d14aa4006
|
||||
timeCreated: 1537501691
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public static class ReflectionBakingInternalUtil
|
||||
{
|
||||
public static string ConvertAssetPathToSystemPath(string assetPath)
|
||||
{
|
||||
string path = Application.dataPath;
|
||||
int pathLength = path.Length;
|
||||
path = path.Substring(0, pathLength - /* Assets */ 6);
|
||||
path = Path.Combine(path, assetPath);
|
||||
return path;
|
||||
}
|
||||
|
||||
public static ZenjectReflectionBakingSettings TryGetEnabledSettingsInstance()
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:ZenjectReflectionBakingSettings");
|
||||
|
||||
if (guids.IsEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ZenjectReflectionBakingSettings enabledSettings = null;
|
||||
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var candidate = AssetDatabase.LoadAssetAtPath<ZenjectReflectionBakingSettings>(
|
||||
AssetDatabase.GUIDToAssetPath(guid));
|
||||
|
||||
if ((Application.isEditor && candidate.IsEnabledInEditor) || (BuildPipeline.isBuildingPlayer && candidate.IsEnabledInBuilds))
|
||||
{
|
||||
Assert.IsNull(enabledSettings, "Found multiple enabled ZenjectReflectionBakingSettings objects! Please disable/delete one to continue.");
|
||||
enabledSettings = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return enabledSettings;
|
||||
}
|
||||
|
||||
public static string ConvertAbsoluteToAssetPath(string systemPath)
|
||||
{
|
||||
var projectPath = Application.dataPath;
|
||||
|
||||
// Remove 'Assets'
|
||||
projectPath = projectPath.Substring(0, projectPath.Length - /* Assets */ 6);
|
||||
|
||||
int systemPathLength = systemPath.Length;
|
||||
int assetPathLength = systemPathLength - projectPath.Length;
|
||||
|
||||
Assert.That(assetPathLength > 0, "Unexpect path '{0}'", systemPath);
|
||||
|
||||
return systemPath.Substring(projectPath.Length, assetPathLength);
|
||||
}
|
||||
|
||||
public static void TryForceUnityFullCompile()
|
||||
{
|
||||
Type compInterface = typeof(UnityEditor.Editor).Assembly.GetType(
|
||||
"UnityEditor.Scripting.ScriptCompilation.EditorCompilationInterface");
|
||||
|
||||
if (compInterface != null)
|
||||
{
|
||||
var dirtyAllScriptsMethod = compInterface.GetMethod(
|
||||
"DirtyAllScripts", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
dirtyAllScriptsMethod.Invoke(null, null);
|
||||
}
|
||||
|
||||
UnityEditor.AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68724c9557073844fb7c3f088c588d32
|
||||
timeCreated: 1537003252
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#if !NOT_UNITY3D
|
||||
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Zenject.Internal;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public static class ReflectionBakingMenuItems
|
||||
{
|
||||
[MenuItem("Assets/Create/Zenject/Reflection Baking Settings", false, 100)]
|
||||
public static void CreateReflectionBakingSettings()
|
||||
{
|
||||
var folderPath = ZenUnityEditorUtil.GetCurrentDirectoryAssetPathFromSelection();
|
||||
|
||||
var config = ScriptableObject.CreateInstance<ZenjectReflectionBakingSettings>();
|
||||
|
||||
ZenUnityEditorUtil.SaveScriptableObjectAsset(
|
||||
Path.Combine(folderPath, "ZenjectReflectionBakingSettings.asset"), config);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 549215a3ba27806449b2b1542fdffc03
|
||||
timeCreated: 1537690031
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Zenject.ReflectionBaking.Mono.Cecil;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public class UnityAssemblyResolver : BaseAssemblyResolver
|
||||
{
|
||||
readonly IDictionary<string, string> _appDomainAssemblyLocations;
|
||||
readonly IDictionary<string, AssemblyDefinition> _cache;
|
||||
|
||||
public UnityAssemblyResolver()
|
||||
{
|
||||
_appDomainAssemblyLocations = new Dictionary<string, string>();
|
||||
_cache = new Dictionary<string, AssemblyDefinition>();
|
||||
|
||||
AppDomain domain = AppDomain.CurrentDomain;
|
||||
|
||||
Assembly[] assemblies = domain.GetAssemblies();
|
||||
|
||||
for (int i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
#if NET_4_6
|
||||
if (assemblies[i].IsDynamic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
_appDomainAssemblyLocations[assemblies[i].FullName] = assemblies[i].Location;
|
||||
|
||||
AddSearchDirectory(Path.GetDirectoryName(assemblies[i].Location));
|
||||
}
|
||||
}
|
||||
|
||||
public override AssemblyDefinition Resolve(AssemblyNameReference name)
|
||||
{
|
||||
AssemblyDefinition assemblyDef = FindAssemblyDefinition(name.FullName, null);
|
||||
|
||||
if (assemblyDef == null)
|
||||
{
|
||||
assemblyDef = base.Resolve(name);
|
||||
_cache[name.FullName] = assemblyDef;
|
||||
}
|
||||
|
||||
return assemblyDef;
|
||||
}
|
||||
|
||||
public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
|
||||
{
|
||||
AssemblyDefinition assemblyDef = FindAssemblyDefinition(name.FullName, parameters);
|
||||
|
||||
if (assemblyDef == null)
|
||||
{
|
||||
assemblyDef = base.Resolve(name, parameters);
|
||||
_cache[name.FullName] = assemblyDef;
|
||||
}
|
||||
|
||||
return assemblyDef;
|
||||
}
|
||||
|
||||
/// Searches for AssemblyDefinition in our cache, and failing that,
|
||||
/// looks for a known location. Returns null if both attempts fail.
|
||||
AssemblyDefinition FindAssemblyDefinition(string fullName, ReaderParameters parameters)
|
||||
{
|
||||
if (fullName == null)
|
||||
{
|
||||
throw new ArgumentNullException("fullName");
|
||||
}
|
||||
|
||||
AssemblyDefinition assemblyDefinition;
|
||||
|
||||
// Look in cache first
|
||||
if (_cache.TryGetValue(fullName, out assemblyDefinition))
|
||||
{
|
||||
return assemblyDefinition;
|
||||
}
|
||||
|
||||
// Try to use known location
|
||||
|
||||
string location;
|
||||
|
||||
if (_appDomainAssemblyLocations.TryGetValue(fullName, out location))
|
||||
{
|
||||
if (parameters != null)
|
||||
{
|
||||
assemblyDefinition = AssemblyDefinition.ReadAssembly(location, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
assemblyDefinition = AssemblyDefinition.ReadAssembly(location);
|
||||
}
|
||||
|
||||
_cache[fullName] = assemblyDefinition;
|
||||
|
||||
return assemblyDefinition;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b107233111f831043b3d5983fe6f1b25
|
||||
timeCreated: 1537934945
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
public class ZenjectReflectionBakingSettings : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
bool _isEnabledInBuilds = true;
|
||||
|
||||
[SerializeField]
|
||||
bool _isEnabledInEditor = false;
|
||||
|
||||
[SerializeField]
|
||||
bool _allGeneratedAssemblies = true;
|
||||
|
||||
[SerializeField]
|
||||
List<string> _includeAssemblies = null;
|
||||
|
||||
[SerializeField]
|
||||
List<string> _excludeAssemblies = null;
|
||||
|
||||
[SerializeField]
|
||||
List<string> _namespacePatterns = null;
|
||||
|
||||
public List<string> NamespacePatterns
|
||||
{
|
||||
get { return _namespacePatterns; }
|
||||
}
|
||||
|
||||
public List<string> IncludeAssemblies
|
||||
{
|
||||
get { return _includeAssemblies; }
|
||||
}
|
||||
|
||||
public List<string> ExcludeAssemblies
|
||||
{
|
||||
get { return _excludeAssemblies; }
|
||||
}
|
||||
|
||||
public bool IsEnabledInEditor
|
||||
{
|
||||
get { return _isEnabledInEditor; }
|
||||
}
|
||||
|
||||
public bool IsEnabledInBuilds
|
||||
{
|
||||
get { return _isEnabledInBuilds; }
|
||||
}
|
||||
|
||||
public bool AllGeneratedAssemblies
|
||||
{
|
||||
get { return _allGeneratedAssemblies; }
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ab372d6a005c8344b5d6b25dbc310ce
|
||||
timeCreated: 1536333743
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.ReflectionBaking
|
||||
{
|
||||
[CustomEditor(typeof(ZenjectReflectionBakingSettings))]
|
||||
public class ZenjectReflectionBakingSettingsEditor : Editor
|
||||
{
|
||||
SerializedProperty _includeAssemblies;
|
||||
SerializedProperty _excludeAssemblies;
|
||||
SerializedProperty _namespacePatterns;
|
||||
SerializedProperty _isEnabledInBuilds;
|
||||
SerializedProperty _isEnabledInEditor;
|
||||
SerializedProperty _allGeneratedAssemblies;
|
||||
|
||||
// Lists
|
||||
ReorderableList _includeAssembliesList;
|
||||
ReorderableList _excludeAssembliesList;
|
||||
ReorderableList _namespacePatternsList;
|
||||
|
||||
// Layouts
|
||||
Vector2 _logScrollPosition;
|
||||
int _selectedLogIndex;
|
||||
|
||||
bool _hasModifiedProperties;
|
||||
|
||||
static GUIContent _includeAssembliesListHeaderContent = new GUIContent
|
||||
{
|
||||
text = "Include Assemblies",
|
||||
tooltip = "The list of all the assemblies that will be editted to have reflection information directly embedded"
|
||||
};
|
||||
|
||||
static GUIContent _excludeAssembliesListHeaderContent = new GUIContent
|
||||
{
|
||||
text = "Exclude Assemblies",
|
||||
tooltip = "The list of all the assemblies that will not be editted"
|
||||
};
|
||||
|
||||
static GUIContent _namespacePatternListHeaderContent = new GUIContent
|
||||
{
|
||||
text = "Namespace Patterns",
|
||||
tooltip = "This list of Regex patterns will be compared to the name of each type in the given assemblies, and when a match is found that type will be editting to directly contain reflection information"
|
||||
};
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_includeAssemblies = serializedObject.FindProperty("_includeAssemblies");
|
||||
_excludeAssemblies = serializedObject.FindProperty("_excludeAssemblies");
|
||||
_namespacePatterns = serializedObject.FindProperty("_namespacePatterns");
|
||||
_isEnabledInEditor = serializedObject.FindProperty("_isEnabledInEditor");
|
||||
_isEnabledInBuilds = serializedObject.FindProperty("_isEnabledInBuilds");
|
||||
_allGeneratedAssemblies = serializedObject.FindProperty("_allGeneratedAssemblies");
|
||||
|
||||
_namespacePatternsList = new ReorderableList(serializedObject, _namespacePatterns);
|
||||
_namespacePatternsList.drawHeaderCallback += OnNamespacePatternsDrawHeader;
|
||||
_namespacePatternsList.drawElementCallback += OnNamespacePatternsDrawElement;
|
||||
|
||||
_includeAssembliesList = new ReorderableList(serializedObject, _includeAssemblies);
|
||||
_includeAssembliesList.drawHeaderCallback += OnIncludeWeavedAssemblyDrawHeader;
|
||||
_includeAssembliesList.onAddCallback += OnIncludeWeavedAssemblyElementAdded;
|
||||
_includeAssembliesList.drawElementCallback += OnIncludeAssemblyListDrawElement;
|
||||
|
||||
_excludeAssembliesList = new ReorderableList(serializedObject, _excludeAssemblies);
|
||||
_excludeAssembliesList.drawHeaderCallback += OnExcludeWeavedAssemblyDrawHeader;
|
||||
_excludeAssembliesList.onAddCallback += OnExcludeWeavedAssemblyElementAdded;
|
||||
_excludeAssembliesList.drawElementCallback += OnExcludeAssemblyListDrawElement;
|
||||
}
|
||||
|
||||
void OnNamespacePatternsDrawElement(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
SerializedProperty indexProperty = _namespacePatterns.GetArrayElementAtIndex(index);
|
||||
indexProperty.stringValue = EditorGUI.TextField(rect, indexProperty.stringValue);
|
||||
}
|
||||
|
||||
void OnExcludeAssemblyListDrawElement(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
SerializedProperty indexProperty = _excludeAssemblies.GetArrayElementAtIndex(index);
|
||||
EditorGUI.LabelField(rect, indexProperty.stringValue, EditorStyles.textArea);
|
||||
}
|
||||
|
||||
void OnIncludeAssemblyListDrawElement(Rect rect, int index, bool isActive, bool isFocused)
|
||||
{
|
||||
SerializedProperty indexProperty = _includeAssemblies.GetArrayElementAtIndex(index);
|
||||
EditorGUI.LabelField(rect, indexProperty.stringValue, EditorStyles.textArea);
|
||||
}
|
||||
|
||||
void OnNamespacePatternsDrawHeader(Rect rect)
|
||||
{
|
||||
GUI.Label(rect, _namespacePatternListHeaderContent);
|
||||
}
|
||||
|
||||
void OnExcludeWeavedAssemblyDrawHeader(Rect rect)
|
||||
{
|
||||
GUI.Label(rect, _excludeAssembliesListHeaderContent);
|
||||
}
|
||||
|
||||
void OnIncludeWeavedAssemblyDrawHeader(Rect rect)
|
||||
{
|
||||
GUI.Label(rect, _includeAssembliesListHeaderContent);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
{
|
||||
GUILayout.Label("Settings", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.PropertyField(_isEnabledInBuilds, true);
|
||||
|
||||
var oldIsEnabledInEditorValue = _isEnabledInEditor.boolValue;
|
||||
EditorGUILayout.PropertyField(_isEnabledInEditor, true);
|
||||
|
||||
if (oldIsEnabledInEditorValue != _isEnabledInEditor.boolValue)
|
||||
{
|
||||
ReflectionBakingInternalUtil.TryForceUnityFullCompile();
|
||||
}
|
||||
|
||||
#if !UNITY_2018_1_OR_NEWER
|
||||
if (_isEnabledInEditor.boolValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"Reflection baking inside unity editor requires Unity 2018+! It is however supported for builds", MessageType.Error);
|
||||
}
|
||||
#endif
|
||||
EditorGUILayout.PropertyField(_allGeneratedAssemblies, true);
|
||||
|
||||
if (_allGeneratedAssemblies.boolValue)
|
||||
{
|
||||
_excludeAssembliesList.DoLayoutList();
|
||||
|
||||
GUI.enabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
_includeAssembliesList.DoLayoutList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
GUI.enabled = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.enabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
_excludeAssembliesList.DoLayoutList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
_includeAssembliesList.DoLayoutList();
|
||||
}
|
||||
|
||||
_namespacePatternsList.DoLayoutList();
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
_hasModifiedProperties = true;
|
||||
}
|
||||
|
||||
if (_hasModifiedProperties)
|
||||
{
|
||||
_hasModifiedProperties = false;
|
||||
ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyModifiedProperties()
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
serializedObject.Update();
|
||||
}
|
||||
|
||||
void OnExcludeWeavedAssemblyElementAdded(ReorderableList list)
|
||||
{
|
||||
OnAssemblyElementAdded(_excludeAssemblies, list);
|
||||
}
|
||||
|
||||
void OnIncludeWeavedAssemblyElementAdded(ReorderableList list)
|
||||
{
|
||||
OnAssemblyElementAdded(_includeAssemblies, list);
|
||||
}
|
||||
|
||||
void OnAssemblyElementAdded(SerializedProperty listProperty, ReorderableList list)
|
||||
{
|
||||
GenericMenu menu = new GenericMenu();
|
||||
|
||||
var paths = AssemblyPathRegistry.GetAllGeneratedAssemblyRelativePaths();
|
||||
|
||||
for (int i = 0; i < paths.Count; i++)
|
||||
{
|
||||
var path = paths[i];
|
||||
|
||||
bool foundMatch = false;
|
||||
|
||||
for (int k = 0; k < listProperty.arraySize; k++)
|
||||
{
|
||||
SerializedProperty current = listProperty.GetArrayElementAtIndex(k);
|
||||
|
||||
if (path == current.stringValue)
|
||||
{
|
||||
foundMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatch)
|
||||
{
|
||||
GUIContent content = new GUIContent(path);
|
||||
menu.AddItem(content, false, p => OnWeavedAssemblyAdded(listProperty, p), path);
|
||||
}
|
||||
}
|
||||
|
||||
if (menu.GetItemCount() == 0)
|
||||
{
|
||||
menu.AddDisabledItem(new GUIContent("[All Assemblies Added]"));
|
||||
}
|
||||
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
|
||||
void OnWeavedAssemblyAdded(SerializedProperty listProperty, object path)
|
||||
{
|
||||
listProperty.arraySize++;
|
||||
SerializedProperty weaved = listProperty.GetArrayElementAtIndex(listProperty.arraySize - 1);
|
||||
weaved.stringValue = ((string)path).Replace("\\", "/");
|
||||
ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90683e755a104ed4ab5841ef7bb58742
|
||||
timeCreated: 1538185954
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Zenject-ReflectionBaking-Editor",
|
||||
"references": [
|
||||
"Zenject",
|
||||
"Zenject-Editor"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": []
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14f8b558cd941e545961d1d8d31254f0
|
||||
timeCreated: 1536994295
|
||||
licenseType: Free
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user