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); }
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); }
/// <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); } }
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!"); } }
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); } } } }
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); } }
/// <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(); }
/// <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(); } } }
/// <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 }
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."); }
/// <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(); } } }
/// <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); } } }