Exemple #1
0
        protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, GUIContent label)
        {
            var eventDrawer = entry.Context.Get(this, "event_drawer", (UnityEditorInternal.UnityEventDrawer)null);

            if (eventDrawer.Value == null)
            {
                eventDrawer.Value = new UnityEditorInternal.UnityEventDrawer();
                this.drawer       = eventDrawer.Value;

                if (UnityPropertyHandlerUtility.IsAvailable)
                {
                    this.propertyHandler = UnityPropertyHandlerUtility.CreatePropertyHandler(this.drawer);
                }
            }

            FieldInfo          fieldInfo;
            SerializedProperty unityProperty = entry.Property.Tree.GetUnityPropertyForPath(entry.Property.Path, out fieldInfo);

            if (unityProperty == null)
            {
                if (UnityVersion.IsVersionOrGreater(2017, 1))
                {
                    this.CallNextDrawer(entry, label);
                    return;
                }
                else if (!typeof(T).IsDefined <SerializableAttribute>())
                {
                    SirenixEditorGUI.ErrorMessageBox("You have likely forgotten to mark your custom UnityEvent class '" + typeof(T).GetNiceName() + "' with the [Serializable] attribute! Could not get a Unity SerializedProperty for the property '" + entry.Property.NiceName + "' of type '" + entry.TypeOfValue.GetNiceName() + "' at path '" + entry.Property.Path + "'.");
                    return;
                }
            }

            base.DrawPropertyLayout(entry, label);
        }
Exemple #2
0
        public static void ResetCustomEditors()
        {
            if (!IsValid)
            {
                return;
            }

            if (UnityVersion.IsVersionOrGreater(2018, 1))
            {
                ((IDictionary)CustomEditorAttributesType_CustomEditors.GetValue(null)).Clear();
                ((IDictionary)CustomEditorAttributesType_CustomMultiEditors.GetValue(null)).Clear();
            }
            else
            {
                if (CustomEditorAttributesType_CachedEditorForType != null)
                {
                    ((Dictionary <Type, Type>)CustomEditorAttributesType_CachedEditorForType.GetValue(null)).Clear();
                }
                if (CustomEditorAttributesType_CachedMultiEditorForType != null)
                {
                    ((Dictionary <Type, Type>)CustomEditorAttributesType_CachedMultiEditorForType.GetValue(null)).Clear();
                }
                ((IList)CustomEditorAttributesType_CustomEditors.GetValue(null)).Clear();
                ((IList)CustomEditorAttributesType_CustomMultiEditors.GetValue(null)).Clear();
            }

            CustomEditorAttributesType_Initialized.SetValue(null, false);
        }
Exemple #3
0
 /// <summary>
 /// Not yet documented.
 /// </summary>
 public AssemblyGenerator()
 {
     if (!UnityVersion.IsVersionOrGreater(5, 5))
     {
         // Make sure mscorlib is always referenced
         this.referencedAssemblies.Add(typeof(string).Assembly.Location);
     }
 }
Exemple #4
0
        static InspectorUtilities()
        {
            string nativeObjectPtrName = UnityVersion.IsVersionOrGreater(2018, 3) ? "m_NativeObjectPtr" : "m_Property";

            var nativeObjectPtrField = typeof(SerializedObject).GetField(nativeObjectPtrName, Flags.InstanceAnyVisibility);

            if (nativeObjectPtrField != null)
            {
                SerializedObject_nativeObjectPtrGetter = EmitUtilities.CreateInstanceFieldGetter <SerializedObject, IntPtr>(nativeObjectPtrField);
            }
            else
            {
                Debug.LogWarning("The internal Unity field SerializedObject.m_Property (< 2018.3)/SerializedObject.m_NativeObjectPtr (>= 2018.3) has been renamed in this version of Unity!");
            }
        }
Exemple #5
0
        public static void SetCustomEditor(Type inspectedType, Type editorType, bool isFallbackEditor, bool isEditorForChildClasses, bool isMultiEditor)
        {
            if (!IsValid)
            {
                return;
            }

            object entry = Activator.CreateInstance(MonoEditorType);

            MonoEditorType_InspectedType.SetValue(entry, inspectedType);
            MonoEditorType_InspectorType.SetValue(entry, editorType);
            MonoEditorType_IsFallback.SetValue(entry, isFallbackEditor);
            MonoEditorType_EditorForChildClasses.SetValue(entry, isEditorForChildClasses);

            if (UnityVersion.IsVersionOrGreater(2018, 1))
            {
                AddEntryToDictList((IDictionary)CustomEditorAttributesType_CustomEditors.GetValue(null), entry, inspectedType);

                if (isMultiEditor)
                {
                    AddEntryToDictList((IDictionary)CustomEditorAttributesType_CustomMultiEditors.GetValue(null), entry, inspectedType);
                }
            }
            else
            {
                if (CustomEditorAttributesType_CachedEditorForType != null && CustomEditorAttributesType_CachedMultiEditorForType != null)
                {
                    // Just set the dictionary cache
                    ((IDictionary)CustomEditorAttributesType_CachedEditorForType.GetValue(null))[inspectedType] = editorType;

                    if (isMultiEditor)
                    {
                        ((IDictionary)CustomEditorAttributesType_CachedMultiEditorForType.GetValue(null))[inspectedType] = editorType;
                    }
                }

                // Insert a new type entry at the beginning of the relevant lists
                {
                    ((IList)CustomEditorAttributesType_CustomEditors.GetValue(null)).Insert(0, entry);

                    if (isMultiEditor)
                    {
                        ((IList)CustomEditorAttributesType_CustomMultiEditors.GetValue(null)).Insert(0, entry);
                    }
                }
            }
        }
Exemple #6
0
        private static void EnsureInitialized()
        {
            if (!Initialized)
            {
                Initialized = true;

                try
                {
                    string haveAudioCallbackName = UnityVersion.IsVersionOrGreater(5, 6) ? "HasAudioCallback" : "HaveAudioCallback";

                    AudioUtil_HaveAudioCallback           = (Func <MonoBehaviour, bool>)Delegate.CreateDelegate(typeof(Func <MonoBehaviour, bool>), typeof(Editor).Assembly.GetType("UnityEditor.AudioUtil").GetMethod(haveAudioCallbackName, BindingFlags.Public | BindingFlags.Static));
                    AudioUtil_GetCustomFilterChannelCount = (Func <MonoBehaviour, int>)Delegate.CreateDelegate(typeof(Func <MonoBehaviour, int>), typeof(Editor).Assembly.GetType("UnityEditor.AudioUtil").GetMethod("GetCustomFilterChannelCount", BindingFlags.Public | BindingFlags.Static));
                    AudioFilterGUIType      = typeof(Editor).Assembly.GetType("UnityEditor.AudioFilterGUI");
                    DrawAudioFilterGUI      = EmitUtilities.CreateWeakInstanceMethodCaller <MonoBehaviour>(AudioFilterGUIType.GetMethod("DrawAudioFilterGUI", BindingFlags.Public | BindingFlags.Instance));
                    HasReflectedAudioFilter = true;
                }
                catch (Exception)
                {
                    Debug.LogWarning("The internal Unity class AudioFilterGUI has been changed; cannot properly mock a generic Unity inspector. This probably won't be very noticeable.");
                }
            }
        }
        public static void ResetCustomEditors()
        {
            if (!IsValid)
            {
                return;
            }

            if (IsBackedByADictionary)
            {
                ((IDictionary)CustomEditorAttributesType_CustomEditors.GetValue(null)).Clear();
                ((IDictionary)CustomEditorAttributesType_CustomMultiEditors.GetValue(null)).Clear();
            }
            else
            {
                if (CustomEditorAttributesType_CachedEditorForType != null)
                {
                    ((Dictionary <Type, Type>)CustomEditorAttributesType_CachedEditorForType.GetValue(null)).Clear();
                }
                if (CustomEditorAttributesType_CachedMultiEditorForType != null)
                {
                    ((Dictionary <Type, Type>)CustomEditorAttributesType_CachedMultiEditorForType.GetValue(null)).Clear();
                }
                ((IList)CustomEditorAttributesType_CustomEditors.GetValue(null)).Clear();
                ((IList)CustomEditorAttributesType_CustomMultiEditors.GetValue(null)).Clear();
            }

            if (UnityVersion.IsVersionOrGreater(2019, 1))
            {
                // Manually trigger a Rebuild instead of setting Initialized to false.
                CustomEditorAttributesType_Rebuild.Invoke(null, null);
                CustomEditorAttributesType_Initialized.SetValue(null, true); // Ensure Unity doesn't do a second rebuild again.
            }
            else
            {
                CustomEditorAttributesType_Initialized.SetValue(null, false);
            }
        }
Exemple #8
0
        /// <summary>
        /// Generates an AOT DLL, using the given parameters.
        /// </summary>
        public static void GenerateDLL(string dirPath, string assemblyName, List <Type> supportSerializedTypes, bool generateLinkXml = true)
        {
            if (!dirPath.EndsWith("/"))
            {
                dirPath += "/";
            }

            var newDllPath  = dirPath + assemblyName;
            var fullDllPath = newDllPath + ".dll";

            var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName()
            {
                Name = assemblyName
            }, AssemblyBuilderAccess.Save, dirPath);
            var module = assembly.DefineDynamicModule(assemblyName);

            assembly.SetCustomAttribute(new CustomAttributeBuilder(typeof(EmittedAssemblyAttribute).GetConstructor(new Type[0]), new object[0]));

            // The following is a fix for Unity's crappy Mono runtime that doesn't know how to do this sort
            //  of stuff properly
            //
            // We must manually remove the "Default Dynamic Assembly" module that is automatically defined,
            //  otherwise a reference to that non-existent module will be saved into the assembly's IL, and
            //  that will cause a multitude of issues.
            //
            // We do this by forcing there to be only one module - the one we just defined, and we set the
            //   manifest module to be that module as well.
            {
                var modulesField        = assembly.GetType().GetField("modules", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var manifestModuleField = assembly.GetType().GetField("manifest_module", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (modulesField != null)
                {
                    modulesField.SetValue(assembly, new ModuleBuilder[] { module });
                }

                if (manifestModuleField != null)
                {
                    manifestModuleField.SetValue(assembly, module);
                }
            }

            var type = module.DefineType(assemblyName + ".PreventCodeStrippingViaReferences", TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic);

            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(PreserveAttribute).GetConstructor(Type.EmptyTypes), new object[0]);

            type.SetCustomAttribute(attributeBuilder);

            var staticConstructor = type.DefineTypeInitializer();
            var il = staticConstructor.GetILGenerator();

            HashSet <Type> seenTypes = new HashSet <Type>();

            //var endPoint = il.DefineLabel();
            //il.Emit(OpCodes.Br, endPoint);

            foreach (var serializedType in supportSerializedTypes)
            {
                if (serializedType == null)
                {
                    continue;
                }

                if (serializedType.IsAbstract || serializedType.IsInterface)
                {
                    Debug.LogError("Skipping type '" + serializedType.GetNiceFullName() + "'! Type is abstract or an interface.");
                    continue;
                }

                if (serializedType.IsGenericType && (serializedType.IsGenericTypeDefinition || !serializedType.IsFullyConstructedGenericType()))
                {
                    Debug.LogError("Skipping type '" + serializedType.GetNiceFullName() + "'! Type is a generic type definition, or its arguments contain generic parameters; type must be a fully constructed generic type.");
                    continue;
                }

                if (seenTypes.Contains(serializedType))
                {
                    continue;
                }

                seenTypes.Add(serializedType);

                // Reference serialized type
                {
                    if (serializedType.IsValueType)
                    {
                        var local = il.DeclareLocal(serializedType);

                        il.Emit(OpCodes.Ldloca, local);
                        il.Emit(OpCodes.Initobj, serializedType);
                    }
                    else
                    {
                        var constructor = serializedType.GetConstructor(Type.EmptyTypes);

                        if (constructor != null)
                        {
                            il.Emit(OpCodes.Newobj, constructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }
                }

                // Reference and/or create formatter type
                if (!FormatterUtilities.IsPrimitiveType(serializedType) && !typeof(UnityEngine.Object).IsAssignableFrom(serializedType))
                {
                    var actualFormatter = FormatterLocator.GetFormatter(serializedType, SerializationPolicies.Unity);

                    if (actualFormatter.GetType().IsDefined <EmittedFormatterAttribute>())
                    {
                        //TODO: Make emitted formatter code compatible with IL2CPP
                        //// Emit an actual AOT formatter into the generated assembly

                        //if (this.emitAOTFormatters)
                        //{
                        //    var emittedFormatter = FormatterEmitter.EmitAOTFormatter(typeEntry.Type, module, SerializationPolicies.Unity);
                        //    var emittedFormatterConstructor = emittedFormatter.GetConstructor(Type.EmptyTypes);

                        //    il.Emit(OpCodes.Newobj, emittedFormatterConstructor);
                        //    il.Emit(OpCodes.Pop);
                        //}
                    }

                    var formatters = FormatterLocator.GetAllCompatiblePredefinedFormatters(serializedType, SerializationPolicies.Unity);

                    foreach (var formatter in formatters)
                    {
                        // Reference the pre-existing formatter

                        var formatterConstructor = formatter.GetType().GetConstructor(Type.EmptyTypes);

                        if (formatterConstructor != null)
                        {
                            il.Emit(OpCodes.Newobj, formatterConstructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }

                    //// Make sure we have a proper reflection formatter variant if all else goes wrong
                    //il.Emit(OpCodes.Newobj, typeof(ReflectionFormatter<>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes));
                    //il.Emit(OpCodes.Pop);
                }

                ConstructorInfo serializerConstructor;

                // Reference serializer variant
                if (serializedType.IsEnum)
                {
                    serializerConstructor = typeof(EnumSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                }
                else
                {
                    serializerConstructor = typeof(ComplexTypeSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                }

                il.Emit(OpCodes.Newobj, serializerConstructor);
                il.Emit(OpCodes.Pop);
            }

            //il.MarkLabel(endPoint);
            il.Emit(OpCodes.Ret);

            type.CreateType();

            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            if (File.Exists(fullDllPath))
            {
                File.Delete(fullDllPath);
            }

            if (File.Exists(fullDllPath + ".meta"))
            {
                File.Delete(fullDllPath + ".meta");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            assembly.Save(assemblyName);

            File.Move(newDllPath, fullDllPath);

            if (generateLinkXml)
            {
                File.WriteAllText(dirPath + "link.xml",
                                  @"<linker>
       <assembly fullname=""" + assemblyName + @""" preserve=""all""/>
</linker>");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            var pluginImporter = PluginImporter.GetAtPath(fullDllPath) as PluginImporter;

            if (pluginImporter != null)
            {
                //pluginImporter.ClearSettings();

                pluginImporter.SetCompatibleWithEditor(false);
                pluginImporter.SetCompatibleWithAnyPlatform(true);

                // Disable for all standalones
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinuxUniversal, false);

                // StandaloneOSXUniversal (<= 2017.2) / StandaloneOSX (>= 2017.3)
                pluginImporter.SetCompatibleWithPlatform((BuildTarget)2, false);

                if (!UnityVersion.IsVersionOrGreater(2017, 3))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)4, false);        // StandaloneOSXIntel
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)27, false);       // StandaloneOSXIntel64
                }

                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);

                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);

                pluginImporter.SaveAndReimport();
            }

            AssetDatabase.SaveAssets();
        }
Exemple #9
0
        /// <summary>
        /// Draws the proprety.
        /// </summary>
        protected override void DrawPropertyLayout(GUIContent label)
        {
            var property = this.Property;
            var entry    = property.ValueEntry;

            if (SetAttribute == null || SetFieldInfo == null)
            {
                SirenixEditorGUI.ErrorMessageBox("Could not find the internal Unity fields 'PropertyDrawer.m_Attribute' or 'PropertyDrawer.m_FieldInfo'; UnityPropertyAttributeDrawer alias '" + typeof(UnityPropertyAttributeDrawer <TDrawer, TAttribute, TAttributeConstraint>).GetNiceName() + "' has been disabled.");
                return;
            }

            if (entry == null)
            {
                SirenixEditorGUI.ErrorMessageBox("Cannot put the attribute '" + typeof(TAttribute) + "' on a property of type '" + property.Info.PropertyType + "'.");
                return;
            }

            FieldInfo          fieldInfo;
            SerializedProperty unityProperty = property.Tree.GetUnityPropertyForPath(property.Path, out fieldInfo);

            if (unityProperty == null)
            {
                if (UnityVersion.IsVersionOrGreater(2017, 1))
                {
                    this.CallNextDrawer(label);
                }
                else
                {
                    SirenixEditorGUI.ErrorMessageBox("Could not get a Unity SerializedProperty for the property '" + property.NiceName + "' of type '" + entry.TypeOfValue.GetNiceName() + "' at path '" + entry.Property.Path + "'.");
                }

                return;
            }

            SetFieldInfo(ref this.drawer, fieldInfo);
            SetAttribute(ref this.drawer, this.Attribute);

            if (unityProperty.serializedObject.targetObject is EmittedScriptableObject)
            {
                var targetObjects = unityProperty.serializedObject.targetObjects;

                for (int i = 0; i < targetObjects.Length; i++)
                {
                    EmittedScriptableObject target = (EmittedScriptableObject)targetObjects[i];
                    target.SetWeakValue(entry.WeakValues[i]);
                }

                unityProperty.serializedObject.Update();
                unityProperty = unityProperty.serializedObject.FindProperty(unityProperty.propertyPath);
            }

            float height;

            if (this.propertyHandler != null)
            {
                height = UnityPropertyHandlerUtility.PropertyHandlerGetHeight(this.propertyHandler, unityProperty.Copy(), label, false);
            }
            else
            {
                height = this.drawer.GetPropertyHeight(unityProperty.Copy(), label);
            }

            Rect position = EditorGUILayout.GetControlRect(false, height);

            if (this.propertyHandler != null)
            {
                UnityPropertyHandlerUtility.PropertyHandlerOnGUI(this.propertyHandler, position, unityProperty, label, false);
            }
            else
            {
                this.drawer.OnGUI(position, unityProperty, label);
            }

            if (unityProperty.serializedObject.targetObject is EmittedScriptableObject)
            {
                unityProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo();
                var targetObjects = unityProperty.serializedObject.targetObjects;

                for (int i = 0; i < targetObjects.Length; i++)
                {
                    EmittedScriptableObject target = (EmittedScriptableObject)targetObjects[i];
                    entry.WeakValues[i] = target.GetWeakValue();
                }
            }
        }
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(IPropertyValueEntry <TDrawnType> entry, GUIContent label)
        {
            if (SetFieldInfo == null)
            {
                SirenixEditorGUI.ErrorMessageBox("Could not find the internal Unity field 'PropertyDrawer.m_FieldInfo'; UnityPropertyDrawer alias '" + typeof(UnityPropertyDrawer <TDrawer, TDrawnType>).GetNiceName() + "' has been disabled.");
                return;
            }

            FieldInfo          fieldInfo;
            SerializedProperty unityProperty = entry.Property.Tree.GetUnityPropertyForPath(entry.Property.Path, out fieldInfo);

            if (unityProperty == null)
            {
                if (UnityVersion.IsVersionOrGreater(2017, 1))
                {
                    this.CallNextDrawer(entry, label);
                }
                else
                {
                    SirenixEditorGUI.ErrorMessageBox("Could not get a Unity SerializedProperty for the property '" + entry.Property.NiceName + "' of type '" + entry.TypeOfValue.GetNiceName() + "' at path '" + entry.Property.Path + "'.");
                }

                return;
            }

            SetFieldInfo(ref this.drawer, fieldInfo);

            if (unityProperty.serializedObject.targetObject is EmittedScriptableObject <TDrawnType> )
            {
                var targetObjects = unityProperty.serializedObject.targetObjects;

                for (int i = 0; i < targetObjects.Length; i++)
                {
                    EmittedScriptableObject <TDrawnType> target = (EmittedScriptableObject <TDrawnType>)targetObjects[i];
                    target.SetValue(entry.Values[i]);
                }

                unityProperty.serializedObject.Update();
            }
            else if (unityProperty.serializedObject.targetObject is EmittedScriptableObject)
            {
                var targetObjects = unityProperty.serializedObject.targetObjects;

                for (int i = 0; i < targetObjects.Length; i++)
                {
                    EmittedScriptableObject target = (EmittedScriptableObject)targetObjects[i];
                    target.SetWeakValue(entry.Values[i]);
                }

                unityProperty.serializedObject.Update();
                unityProperty = unityProperty.serializedObject.FindProperty(unityProperty.propertyPath);
            }

            float height   = this.drawer.GetPropertyHeight(unityProperty, label);
            Rect  position = EditorGUILayout.GetControlRect(false, height);

            EditorGUI.BeginChangeCheck();

            if (this.propertyHandler != null)
            {
                UnityPropertyHandlerUtility.PropertyHandlerOnGUI(this.propertyHandler, position, unityProperty, label, false);
            }
            else
            {
                this.drawer.OnGUI(position, unityProperty, label);
            }

            bool changed = EditorGUI.EndChangeCheck();

            if (unityProperty.serializedObject.targetObject is EmittedScriptableObject <TDrawnType> )
            {
                if (unityProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo() || changed)
                {
                    var targetObjects = unityProperty.serializedObject.targetObjects;

                    for (int i = 0; i < targetObjects.Length; i++)
                    {
                        EmittedScriptableObject <TDrawnType> target = (EmittedScriptableObject <TDrawnType>)targetObjects[i];
                        entry.Values[i] = target.GetValue();
                    }

                    entry.Values.ForceMarkDirty();
                }
            }
            else if (unityProperty.serializedObject.targetObject is EmittedScriptableObject)
            {
                if (unityProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo() || changed)
                {
                    var targetObjects = unityProperty.serializedObject.targetObjects;

                    for (int i = 0; i < targetObjects.Length; i++)
                    {
                        EmittedScriptableObject target = (EmittedScriptableObject)targetObjects[i];
                        entry.Values[i] = (TDrawnType)target.GetWeakValue();
                    }

                    entry.Values.ForceMarkDirty();
                }
            }
        }
Exemple #11
0
        /// <summary>
        /// Generates an AOT DLL, using the given parameters.
        /// </summary>
        public static void GenerateDLL(string dirPath, string assemblyName, List <Type> supportSerializedTypes, bool generateLinkXml = true)
        {
            #if UNITY_EDITOR && NET_4_6
            if (!dirPath.EndsWith("/"))
            {
                dirPath += "/";
            }

            var newDllPath  = dirPath + assemblyName;
            var fullDllPath = newDllPath + ".dll";

            var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName()
            {
                Name = assemblyName
            }, AssemblyBuilderAccess.Save, dirPath);
            var module = assembly.DefineDynamicModule(assemblyName);

            assembly.SetCustomAttribute(new CustomAttributeBuilder(typeof(EmittedAssemblyAttribute).GetConstructor(new Type[0]), new object[0]));

            // VRChat Edit: Add the UnityAPICompatibilityVersion Attribute for the current version of Unity to skip API Updating.
            #if UNITY_2019
            assembly.SetCustomAttribute(new CustomAttributeBuilder(
                                            typeof(UnityAPICompatibilityVersionAttribute).GetConstructor(new[] { typeof(string), typeof(bool) }),
                                            new object[] { Application.unityVersion, true })
                                        );
            #else
            assembly.SetCustomAttribute(new CustomAttributeBuilder(
                                            typeof(UnityAPICompatibilityVersionAttribute).GetConstructor(new[] { typeof(string) }),
                                            new object[] { Application.unityVersion })
                                        );
            #endif

            // The following is a fix for Unity's crappy Mono runtime that doesn't know how to do this sort
            //  of stuff properly
            //
            // We must manually remove the "Default Dynamic Assembly" module that is automatically defined,
            //  otherwise a reference to that non-existent module will be saved into the assembly's IL, and
            //  that will cause a multitude of issues.
            //
            // We do this by forcing there to be only one module - the one we just defined, and we set the
            //   manifest module to be that module as well.
            {
                var modulesField        = assembly.GetType().GetField("modules", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var manifestModuleField = assembly.GetType().GetField("manifest_module", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (modulesField != null)
                {
                    modulesField.SetValue(assembly, new ModuleBuilder[] { module });
                }

                if (manifestModuleField != null)
                {
                    manifestModuleField.SetValue(assembly, module);
                }
            }

            var type = module.DefineType(assemblyName + ".PreventCodeStrippingViaReferences", TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic);

            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(PreserveAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
            type.SetCustomAttribute(attributeBuilder);

            var staticConstructor = type.DefineTypeInitializer();
            var il = staticConstructor.GetILGenerator();

            var falseLocal = il.DeclareLocal(typeof(bool));

            il.Emit(OpCodes.Ldc_I4_0);                  // Load false
            il.Emit(OpCodes.Stloc, falseLocal);         // Set to falseLocal

            HashSet <Type> seenTypes = new HashSet <Type>();

            if (UnityVersion.Major == 2019 && UnityVersion.Minor == 2)
            {
                // This here is a hack that fixes Unity's assembly updater triggering faultily in Unity 2019.2
                // (and in early 2019.3 alphas/betas, but we're not handling those). When it triggers, it edits
                // the generated AOT assembly such that it immediately causes Unity to hard crash. Having this
                // type reference present in the assembly prevents that from happening. (Any concrete type in
                // the serialization assembly would work, this one is just a random pick.)
                //
                // Unity should have fixed this in 2019.3, but said that a backport to 2019.2 is not guaranteed
                // to occur, though it might.

                supportSerializedTypes.Add(typeof(DateTimeFormatter));
            }

            //var endPoint = il.DefineLabel();
            //il.Emit(OpCodes.Br, endPoint);

            foreach (var serializedType in supportSerializedTypes)
            {
                if (serializedType == null)
                {
                    continue;
                }

                bool isAbstract = serializedType.IsAbstract || serializedType.IsInterface;

                if (serializedType.IsGenericType && (serializedType.IsGenericTypeDefinition || !serializedType.IsFullyConstructedGenericType()))
                {
                    Debug.LogError("Skipping type '" + serializedType.GetNiceFullName() + "'! Type is a generic type definition, or its arguments contain generic parameters; type must be a fully constructed generic type.");
                    continue;
                }

                if (seenTypes.Contains(serializedType))
                {
                    continue;
                }

                seenTypes.Add(serializedType);

                // Reference serialized type
                {
                    if (serializedType.IsValueType)
                    {
                        var local = il.DeclareLocal(serializedType);

                        il.Emit(OpCodes.Ldloca, local);
                        il.Emit(OpCodes.Initobj, serializedType);
                    }
                    else if (!isAbstract)
                    {
                        var constructor = serializedType.GetConstructor(Type.EmptyTypes);

                        if (constructor != null)
                        {
                            il.Emit(OpCodes.Newobj, constructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }
                }

                // Reference and/or create formatter type
                if (!FormatterUtilities.IsPrimitiveType(serializedType) && !typeof(UnityEngine.Object).IsAssignableFrom(serializedType) && !isAbstract)
                {
                    var actualFormatter = FormatterLocator.GetFormatter(serializedType, SerializationPolicies.Unity);

                    if (actualFormatter.GetType().IsDefined <EmittedFormatterAttribute>())
                    {
                        //TODO: Make emitted formatter code compatible with IL2CPP
                        //// Emit an actual AOT formatter into the generated assembly

                        //if (this.emitAOTFormatters)
                        //{
                        //    var emittedFormatter = FormatterEmitter.EmitAOTFormatter(typeEntry.Type, module, SerializationPolicies.Unity);
                        //    var emittedFormatterConstructor = emittedFormatter.GetConstructor(Type.EmptyTypes);

                        //    il.Emit(OpCodes.Newobj, emittedFormatterConstructor);
                        //    il.Emit(OpCodes.Pop);
                        //}
                    }

                    var formatters = FormatterLocator.GetAllCompatiblePredefinedFormatters(serializedType, SerializationPolicies.Unity);

                    foreach (var formatter in formatters)
                    {
                        // Reference the pre-existing formatter

                        var formatterConstructor = formatter.GetType().GetConstructor(Type.EmptyTypes);

                        if (formatterConstructor != null)
                        {
                            il.Emit(OpCodes.Newobj, formatterConstructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }

                    //// Make sure we have a proper reflection formatter variant if all else goes wrong
                    //il.Emit(OpCodes.Newobj, typeof(ReflectionFormatter<>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes));
                    //il.Emit(OpCodes.Pop);
                }

                ConstructorInfo serializerConstructor;

                // Reference serializer variant
                if (serializedType.IsValueType)
                {
                    serializerConstructor = Serializer.Get(serializedType).GetType().GetConstructor(Type.EmptyTypes);

                    il.Emit(OpCodes.Newobj, serializerConstructor);

                    // The following section is a fix for an issue on IL2CPP for PS4, where sometimes bytecode isn't
                    //   generated for methods in base types of needed types - FX, Serializer<T>.ReadValueWeak()
                    //   may be missing. This only seems to happen in a relevant way for value types.
                    {
                        var endLabel = il.DefineLabel();

                        // Load a false local value, then jump to the end of this segment of code due to that
                        //   false value. This is an attempt to trick any potential code flow analysis made
                        //   by IL2CPP that checks whether this segment of code is actually run.
                        //
                        // We don't run the code because if we did, that would actually throw a bunch of
                        //   exceptions from invalid calls to ReadValueWeak and WriteValueWeak.
                        il.Emit(OpCodes.Ldloc, falseLocal);
                        il.Emit(OpCodes.Brfalse, endLabel);

                        var baseSerializerType = typeof(Serializer <>).MakeGenericType(serializedType);

                        var readValueWeakMethod  = baseSerializerType.GetMethod("ReadValueWeak", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, new Type[] { typeof(IDataReader) }, null);
                        var writeValueWeakMethod = baseSerializerType.GetMethod("WriteValueWeak", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, new Type[] { typeof(string), typeof(object), typeof(IDataWriter) }, null);

                        il.Emit(OpCodes.Dup);                               // Duplicate serializer instance
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for IDataReader reader
                        il.Emit(OpCodes.Callvirt, readValueWeakMethod);     // Call ReadValueWeak on serializer instance
                        il.Emit(OpCodes.Pop);                               // Pop result of ReadValueWeak

                        il.Emit(OpCodes.Dup);                               // Duplicate serializer instance
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for string name
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for object value
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for IDataWriter writer
                        il.Emit(OpCodes.Callvirt, writeValueWeakMethod);    // Call WriteValueWeak on serializer instance

                        il.MarkLabel(endLabel);                             // This is where the code always jumps to, skipping the above
                    }

                    il.Emit(OpCodes.Pop);       // Pop the serializer instance
                }
                else
                {
                    serializerConstructor = typeof(ComplexTypeSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                    il.Emit(OpCodes.Newobj, serializerConstructor);
                    il.Emit(OpCodes.Pop);
                }
            }

            //il.MarkLabel(endPoint);
            il.Emit(OpCodes.Ret);

            type.CreateType();

            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            if (File.Exists(fullDllPath))
            {
                File.Delete(fullDllPath);
            }

            if (File.Exists(fullDllPath + ".meta"))
            {
                File.Delete(fullDllPath + ".meta");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            assembly.Save(assemblyName);

            File.Move(newDllPath, fullDllPath);

            if (generateLinkXml)
            {
                File.WriteAllText(dirPath + "link.xml",
                                  @"<linker>
       <assembly fullname=""" + assemblyName + @""" preserve=""all""/>
</linker>");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            var pluginImporter = PluginImporter.GetAtPath(fullDllPath) as PluginImporter;

            if (pluginImporter != null)
            {
                //pluginImporter.ClearSettings();

                pluginImporter.SetCompatibleWithEditor(false);
                pluginImporter.SetCompatibleWithAnyPlatform(true);

                // Disable for all standalones
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);

                if (!UnityVersion.IsVersionOrGreater(2019, 2))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)17, false);       // StandaloneLinux
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)25, false);       // StandaloneLinuxUniversal
                }

                // StandaloneOSXUniversal (<= 2017.2) / StandaloneOSX (>= 2017.3)
                pluginImporter.SetCompatibleWithPlatform((BuildTarget)2, false);

                if (!UnityVersion.IsVersionOrGreater(2017, 3))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)4, false);        // StandaloneOSXIntel
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)27, false);       // StandaloneOSXIntel64
                }

                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);

                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);

                pluginImporter.SaveAndReimport();
            }

            AssetDatabase.SaveAssets();
            #endif
        }
Exemple #12
0
        private static string GuessWhyUnityDoesNotSupport(Type type)
        {
            if (type == typeof(Coroutine))
            {
                return(" because Unity will never serialize Coroutines.");
            }
            if (typeof(Delegate).IsAssignableFrom(type))
            {
                return(" because Unity does not support delegates.");
            }
            if (type.IsInterface)
            {
                return(" because the type is an interface.");
            }
            if (type.IsAbstract)
            {
                return(" because the type is abstract.");
            }
            if (type == typeof(System.Object))
            {
                return(" because Unity does not support serializing System.Object.");
            }
            if (typeof(Enum).IsAssignableFrom(type))
            {
                Type underlying = Enum.GetUnderlyingType(type);

                if (UnityVersion.IsVersionOrGreater(5, 6) && (underlying == typeof(long) || underlying == typeof(ulong)))
                {
                    return(" because Unity does not support enums with underlying type of long or ulong.");
                }
                else if (UnityVersion.Major <= 5 && UnityVersion.Minor < 6 && underlying != typeof(int) && underlying != typeof(byte))
                {
                    return(" because prior to Version 5.6 Unity only supports enums with underlying type of int or byte.");
                }

                return(". Was unable to determine why Unity does not support enum with underlying type of: " + underlying.GetNiceName() + ".");
            }
            if (typeof(UnityEngine.Events.UnityEventBase).IsAssignableFrom(type) && type.IsGenericType)
            {
                return(" because the type is a generic implementation of UnityEventBase.");
            }

            if (type.IsArray)
            {
                if (type.GetArrayRank() > 1 || type.GetElementType().IsArray || type.GetElementType().ImplementsOpenGenericClass(typeof(List <>)))
                {
                    return(" because Unity does not support multi-dimensional arrays.");
                }
                else if (UnitySerializationUtility.GuessIfUnityWillSerialize(type.GetElementType()) == false)
                {
                    return(" because Unity does not support the type " + type.GetElementType().GetNiceName() + " as an array element.");
                }
            }

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>))
            {
                var elementType = type.GetArgumentsOfInheritedOpenGenericClass(typeof(List <>))[0];
                if (elementType.IsArray)
                {
                    return(" because Unity does not support Lists of arrays.");
                }
                else if (elementType.ImplementsOpenGenericClass(typeof(List <>)))
                {
                    return(" because Unity does not support Lists of Lists.");
                }
                else if (UnitySerializationUtility.GuessIfUnityWillSerialize(elementType) == false)
                {
                    return(" because Unity does not support the element type of " + elementType.GetNiceName() + ".");
                }
            }

            if (type.IsGenericType || type.GetGenericArguments().Length > 0)
            {
                return(" because Unity does not support generic types.");
            }

            if (type.Assembly == typeof(string).Assembly)
            {
                return(" because Unity does not serialize [Serializable] structs and classes if they are defined in mscorlib.");
            }

            if (type.IsDefined <SerializableAttribute>(false) == false)
            {
                return(" because the type is missing a [Serializable] attribute.");
            }

            // No reason found.
            return(". Was unable to determine reason, please report this to Sirenix.");
        }
Exemple #13
0
        /// <summary>
        /// Not yet documented.
        /// </summary>
        public bool Compile(string assemblyPath, bool isUnityAssetsPath = true)
        {
            if (assemblyPath == null)
            {
                throw new ArgumentNullException("assemblyPath");
            }

            this.CheckNotCompiledOrDisposed();
            this.hasCompiled = true;

            if (isUnityAssetsPath)
            {
                assemblyPath = Application.dataPath.TrimEnd('/') + "/" + assemblyPath;
            }

            DirectoryInfo assemblyDir = new DirectoryInfo(Path.GetDirectoryName(assemblyPath));

            if (!assemblyDir.Exists)
            {
                assemblyDir.Create();
            }

            // Project/Assets folder
            DirectoryInfo assetsDir = new DirectoryInfo(Application.dataPath);

            // Project folder
            string projectFolderPath = assetsDir.Parent.FullName + "/";
            string tempPath          = projectFolderPath + "Temp/CodeGeneration-" + Guid.NewGuid().ToString() + "/";

            Directory.CreateDirectory(tempPath);

            bool shouldKeepFiles = this.keepFiles;

            try
            {
                if (this.referenceUnityAssemblies)
                {
                    if (this.includeEditorAssemblies)
                    {
                        if (!UnityVersion.IsVersionOrGreater(5, 5))
                        {
                            this.referencedAssemblies.AddRange(AppDomain.CurrentDomain
                                                               .GetAssemblies()
                                                               .Where(ass => ass.GetName().Name.StartsWith("Unity"))
                                                               .Select(ass => ass.Location));
                        }
                    }
                    else
                    {
                        if (!UnityVersion.IsVersionOrGreater(5, 5))
                        {
                            this.referencedAssemblies.AddRange(AppDomain.CurrentDomain
                                                               .GetAssemblies()
                                                               .Where(ass => ass.GetName().Name.StartsWith("UnityEngine"))
                                                               .Select(ass => ass.Location));
                        }
                    }
                }

                DirectoryInfo userScriptAssembliesFolder = new DirectoryInfo(projectFolderPath + "Library/ScriptAssemblies");

                if (this.referenceUserScriptAssemblies && userScriptAssembliesFolder.Exists)
                {
                    FileInfo[] files = userScriptAssembliesFolder.GetFiles("*.dll", SearchOption.AllDirectories);

                    for (int i = 0; i < files.Length; i++)
                    {
                        FileInfo file = files[i];

                        if (file.Extension.ToLowerInvariant() != ".dll")
                        {
                            continue;
                        }

                        bool isEditor = file.Name.Contains("Editor");
                        bool isPlugin = file.Name.Contains("firstpass");

                        bool include = (isPlugin || this.includeNonPluginUserScriptAssemblies) &&
                                       (!isEditor || this.includeEditorAssemblies);

                        if (include)
                        {
                            this.referencedAssemblies.Add(file.FullName);
                        }
                    }
                }

                if (this.includeActiveUnityDefines)
                {
                    this.defines.AddRange(EditorUserBuildSettings.activeScriptCompilationDefines);
                }

                string[] filePaths = new string[this.codeWriters.Count];

                int counter = 0;

                foreach (var pair in this.codeWriters)
                {
                    string path = tempPath + pair.Key;
                    filePaths[counter++] = path;

                    using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                        using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
                        {
                            string code = pair.Value.GetFinalCode();
                            writer.Write(code);
                        }
                }

                var arr = this.referencedAssemblies.Prepend(this.externAliases.Select(n => n.Key + "=" + n.Value))
                          .ToArray();

                //Debug.Log("Referenced assemblies...");
                //arr.ForEach(n => Debug.Log(n));

                string[] messages = EditorUtility.CompileCSharp(filePaths, arr, this.defines.ToArray(), assemblyPath);

                if (messages.Length == 0)
                {
                    return(true);
                }

                if (this.keepFilesOnError)
                {
                    shouldKeepFiles = true;
                }

                if (this.logErrors)
                {
                    Debug.LogWarning("The following " + messages.Length + " errors occurred while compiling a generated assembly at '" + assemblyPath + "':");

                    if (this.keepFilesOnError)
                    {
                        Debug.LogWarning("        ( You can view the faulty source code files at the path '" + tempPath + "'. They will remain until Unity is restarted. )");
                    }

                    for (int i = 0; i < messages.Length; i++)
                    {
                        Debug.LogError("        " + messages[i]);
                    }
                }

                return(false);
            }
            catch (Exception ex)
            {
                Debug.Log("The following exception was thrown while compiling generated code:");
                Debug.LogException(ex);
                return(false);
            }
            finally
            {
                if (!shouldKeepFiles)
                {
                    Directory.Delete(tempPath, true);
                }

                foreach (var writer in this.codeWriters.Values)
                {
                    writer.Dispose();
                }
            }
        }
Exemple #14
0
        /// <summary>
        /// Not yet documented.
        /// </summary>
        public void AddReferencedAssembly(Assembly assembly)
        {
            this.CheckNotCompiledOrDisposed();

            if (assembly == null)
            {
                throw new ArgumentNullException("assembly");
            }

            if (UnityVersion.IsVersionOrGreater(5, 5))
            {
                var assName = assembly.GetName().Name;

                switch (assName)
                {
                // In 5.5 or greater, Unity automatically adds these, always, without checking first whether they're already there
                // Hence, we never add them; this list was simply arrived at by trial and error

                case "mscorlib":
                case "System.Runtime.Serialization":
                case "System.Xml.Linq":
                case "UnityScript":
                case "UnityScript.Lang":
                case "Boo.Lang":
                case "System":
                case "System.Xml":
                case "System.Core":
                    return;
                }
            }

            if (!this.referencedAssemblies.Contains(assembly.Location))
            {
                this.referencedAssemblies.Add(assembly.Location);

                foreach (var name in assembly.GetReferencedAssemblies())
                {
                    Assembly referencedAssembly = AppDomain.CurrentDomain.GetAssemblies()
                                                  .FirstOrDefault(ass => ass.GetName().Name == name.Name);

                    if (referencedAssembly == null)
                    {
                        //Debug.LogWarning("Assembly dependency " + name.Name + " with url '" + name.CodeBase + "' was not loaded in the current AppDomain; trying to load so further dependencies can be resolved.");

                        try
                        {
                            referencedAssembly = Assembly.Load(name);
                        }
                        catch
                        {
                            // Ignore errors here; we give an error message further down if this went wrong
                        }
                    }

                    if (referencedAssembly == null)
                    {
                        Debug.LogError("Failed to find assembly dependency '" + name.FullName + "'! Editor compilation may fail!");
                        continue;
                    }

                    this.AddReferencedAssembly(referencedAssembly);
                }
            }
        }