1
- using System . Collections . Generic ;
2
1
using UnityEditor ;
3
2
using UnityEngine ;
4
3
using System ;
5
4
using System . Linq ;
6
- using System . Runtime . Serialization ;
7
5
using System . Reflection ;
8
- using System . Text . RegularExpressions ;
9
6
using System . Collections ;
7
+ using System . Collections . Generic ;
8
+ using System . Runtime . Serialization ;
9
+ using System . Text . RegularExpressions ;
10
10
11
11
namespace Core
12
12
{
13
13
[ CustomPropertyDrawer ( typeof ( SerializeExtensionAttribute ) ) ]
14
14
public class SerializeExtensionDrawer : PropertyDrawer
15
15
{
16
- private static LogicAndStack _guiEnableStack = new ( ) ;
16
+ private static readonly LogicAndStack _guiEnableStack = new ( ) ;
17
17
18
18
public override float GetPropertyHeight ( SerializedProperty property , GUIContent label ) {
19
19
return property . isExpanded ? EditorGUI . GetPropertyHeight ( property , true ) : EditorGUIUtility . singleLineHeight ;
20
20
}
21
21
22
22
private new SerializeExtensionAttribute attribute => ( SerializeExtensionAttribute ) base . attribute ;
23
23
24
-
25
24
public override void OnGUI ( Rect position , SerializedProperty property , GUIContent label ) {
26
- if ( attribute . NameInEditorWindow != null ) {
27
- label . text = attribute . NameInEditorWindow ;
28
- }
29
- if ( attribute . ToolTips != null ) {
30
- label . tooltip = attribute . ToolTips ;
31
- }
32
-
33
- Type fieldType = null ;
34
- bool isUnityObject = typeof ( UnityEngine . Object ) . IsAssignableFrom ( fieldInfo . FieldType ) ;
35
- if ( isUnityObject || fieldInfo . FieldType . IsValueType || property . propertyType != SerializedPropertyType . ManagedReference ) {
36
- fieldType = fieldInfo . FieldType ;
37
- }
38
- else {
39
- string [ ] info = property . managedReferenceFieldTypename . Split ( ) ;
40
- string asseblyName = info [ 0 ] , typeName = info [ 1 ] ;
41
- Assembly assembly = AppDomain . CurrentDomain . GetAssemblies ( ) . FirstOrDefault ( item => item . GetName ( ) . Name == asseblyName ) ;
42
- fieldType = assembly . GetType ( typeName ) ;
43
- }
44
-
45
- var owner = GetFieldOwner ( property ) ;
46
- PropertyInfo proxy = null ;
47
- bool proxyIsValid = false ;
48
- if ( attribute . ProxyPropertyName != null && ( fieldType . IsValueType || isUnityObject ) ) {
49
- proxy = owner . GetType ( ) . GetProperty ( attribute . ProxyPropertyName , BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ) ;
50
- proxyIsValid = CheckPropertyProxyValid ( proxy , owner , fieldType ) ;
51
- }
25
+ label . text = attribute . NameInEditorWindow ?? label . text ;
26
+ label . tooltip = attribute . ToolTips ?? label . tooltip ;
52
27
53
28
GUI . enabled = _guiEnableStack . Push ( attribute . CanWrite ) ;
54
29
EditorGUI . BeginProperty ( position , label , property ) ;
55
30
EditorGUI . BeginChangeCheck ( ) ;
31
+
32
+ Type fieldType = fieldInfo . FieldType ;
56
33
if ( fieldType . IsAbstract || fieldType . IsInterface ) {
57
- ShowPolymorphismField ( fieldType , position , property , label ) ;
34
+ ShowPolymorphismField ( position , property , label ) ;
58
35
}
59
36
else {
60
37
EditorGUI . PropertyField ( position , property , label , true ) ;
61
38
}
62
39
63
40
bool hasValueUpdated = EditorGUI . EndChangeCheck ( ) || ! attribute . CanWrite ; // !attribute.CanWrite : 当变量不可写时大概率用作显示某个字段的成员信息,为了避免字段发生修改时成员信息更新不同步的问题需要保持更新才行
64
- if ( proxyIsValid && hasValueUpdated ) {
65
- property . serializedObject . ApplyModifiedProperties ( ) ;
66
- if ( proxy . CanRead && proxy . CanWrite ) {
67
- proxy . SetValue ( owner , proxy . GetValue ( owner ) ) ;
68
- }
69
- else if ( proxy . CanRead ) {
70
- fieldInfo . SetValue ( owner , proxy . GetValue ( owner ) ) ;
71
- }
72
- else if ( proxy . CanWrite ) {
73
- proxy . SetValue ( owner , fieldInfo . GetValue ( owner ) ) ;
41
+ bool canSerializeType = typeof ( UnityEngine . Object ) . IsAssignableFrom ( fieldType ) || fieldType . IsValueType ;
42
+ if ( hasValueUpdated && canSerializeType && attribute . ProxyPropertyName != null ) {
43
+ var owner = GetFieldOwner ( property ) ;
44
+ PropertyInfo proxy = owner . GetType ( ) . GetProperty ( attribute . ProxyPropertyName , BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Public ) ; ;
45
+ if ( CheckPropertyProxyValid ( proxy , owner , fieldType ) ) {
46
+ property . serializedObject . ApplyModifiedProperties ( ) ;
47
+ if ( proxy . CanRead && proxy . CanWrite ) {
48
+ proxy . SetValue ( owner , proxy . GetValue ( owner ) ) ;
49
+ }
50
+ else if ( proxy . CanRead ) {
51
+ fieldInfo . SetValue ( owner , proxy . GetValue ( owner ) ) ;
52
+ }
53
+ else if ( proxy . CanWrite ) {
54
+ proxy . SetValue ( owner , fieldInfo . GetValue ( owner ) ) ;
55
+ }
74
56
}
75
57
}
58
+
76
59
GUI . enabled = _guiEnableStack . Pop ( ) ;
77
60
EditorGUI . EndProperty ( ) ;
78
61
}
79
62
80
63
#region Show Polymorphism Field
81
64
private readonly static Dictionary < Type , List < Type > > _subTypeDict = new ( ) ;
82
65
83
- private void ShowPolymorphismField ( Type abstractType , Rect position , SerializedProperty property , GUIContent label ) {
66
+ private void ShowPolymorphismField ( Rect position , SerializedProperty property , GUIContent label ) {
67
+ // 绘制选择框
68
+ Type abstractType = fieldInfo . FieldType ;
69
+ List < Type > subTypes = GetSubTypes ( abstractType ) ;
70
+
84
71
Rect labelRect = EditorGUI . IndentedRect ( new ( position ) {
85
72
height = EditorGUIUtility . singleLineHeight
86
73
} ) ;
87
74
Rect popupRect = EditorGUI . PrefixLabel ( labelRect , label ) ;
88
- if ( attribute . CanSwitchSubType ) {
89
- var subTypes = GetSubTypes ( abstractType ) ;
90
75
91
- var fieldType = property . managedReferenceValue ? . GetType ( ) ;
92
- int currentIndex = subTypes . FindIndex ( type => type == fieldType ) + 1 ; // 会占用选择框0号位置为"None (null)" 所以下标会加一个偏移量
93
- string [ ] selectBoxText = subTypes . Select ( type => type . Name ) . Prepend ( "None (null)" ) . ToArray ( ) ;
76
+ string [ ] selectBoxTexts = subTypes . Select ( type => type . Name ) . Prepend ( "None (null)" ) . ToArray ( ) ;
77
+ Type fieldType = property . managedReferenceValue ? . GetType ( ) ;
78
+ int currentIndex = subTypes . FindIndex ( type => type == fieldType ) + 1 ; // 选择框会占用0号位置为 "None (null)" 所以下标会加一个偏移量
94
79
95
- int newSelectIndex = EditorGUI . Popup ( popupRect , currentIndex , selectBoxText ) ;
96
- if ( newSelectIndex != currentIndex ) {
97
- if ( newSelectIndex == 0 ) {
98
- property . managedReferenceValue = null ;
99
- }
100
- else {
101
- bool hasDefaultConstructor = false ;
102
-
103
- Type type = subTypes [ newSelectIndex - 1 ] ; // 将选择框的一个偏移量减回来
104
- ConstructorInfo [ ] constructors = type . GetConstructors ( ) ;
105
- // 查找无参构造函数
106
- foreach ( var constructor in constructors ) {
107
- if ( constructor . GetParameters ( ) . Length == 0 ) {
108
- // 调用无参构造函数并返回实例
109
- hasDefaultConstructor = true ;
110
- property . managedReferenceValue = constructor . Invoke ( null ) ;
111
- }
112
- }
113
-
114
- if ( ! hasDefaultConstructor ) {
115
- property . managedReferenceValue = FormatterServices . GetSafeUninitializedObject ( type ) ;
116
- }
117
- }
118
- property . serializedObject . ApplyModifiedProperties ( ) ; //更改多态类型后必须马上保存,否则后续序列化可能会出现异常
80
+ GUI . enabled = attribute . CanSwitchSubType ;
81
+ int newSelectIndex = EditorGUI . Popup ( popupRect , currentIndex , selectBoxTexts ) ;
82
+ GUI . enabled = true ;
83
+
84
+ if ( newSelectIndex != currentIndex ) {
85
+ if ( newSelectIndex == 0 ) {
86
+ property . managedReferenceValue = null ;
87
+ }
88
+ else {
89
+ Type type = subTypes [ newSelectIndex - 1 ] ; // 将选择框的一个偏移量减回来
90
+ property . managedReferenceValue = CreateInstance ( type ) ;
119
91
}
92
+ property . serializedObject . ApplyModifiedProperties ( ) ; //更改多态类型后必须马上保存,否则后续序列化可能会出现异常
120
93
}
121
94
95
+ // 绘制序列化字段
122
96
Rect foldoutRect = new ( position ) {
123
97
height = EditorGUIUtility . singleLineHeight
124
98
} ;
@@ -135,30 +109,50 @@ private void ShowPolymorphismField(Type abstractType, Rect position, SerializedP
135
109
}
136
110
}
137
111
}
112
+ }
138
113
139
- static List < Type > GetSubTypes ( Type abstractType ) {
140
- if ( ! _subTypeDict . TryGetValue ( abstractType , out var subTypes ) ) {
141
- subTypes = AppDomain . CurrentDomain . GetAssemblies ( )
142
- . SelectMany ( assembly => assembly . GetTypes ( ) )
143
- . Where ( type => abstractType . IsAssignableFrom ( type ) && ! type . IsAbstract && ! type . IsInterface )
144
- . ToList ( ) ;
114
+ private List < Type > GetSubTypes ( Type abstractType ) {
115
+ if ( ! _subTypeDict . TryGetValue ( abstractType , out var subTypes ) ) {
116
+ subTypes = AppDomain . CurrentDomain . GetAssemblies ( )
117
+ . SelectMany ( assembly => assembly . GetTypes ( ) )
118
+ . Where ( type => abstractType . IsAssignableFrom ( type ) && ! type . IsAbstract && ! type . IsInterface )
119
+ . ToList ( ) ;
145
120
146
- const int maxCacheSize = 10 ;
147
- while ( _subTypeDict . Count > maxCacheSize ) {
148
- _subTypeDict . Remove ( _subTypeDict . Keys . First ( ) ) ;
149
- }
150
- _subTypeDict . Add ( abstractType , subTypes ) ;
121
+ const int maxCacheSize = 10 ;
122
+ while ( _subTypeDict . Count > maxCacheSize ) {
123
+ _subTypeDict . Remove ( _subTypeDict . Keys . First ( ) ) ;
151
124
}
152
- return subTypes ;
125
+ _subTypeDict . Add ( abstractType , subTypes ) ;
153
126
}
127
+ return subTypes ;
128
+ }
154
129
155
- //void SetPropertymanagedReferenceValue(List<Type> subTypes, int selectIndex) {
156
- // if (selectIndex == curIndex || selectIndex < 0 || selectIndex >= subTypes.Count) return;
157
- // property.managedReferenceValue = FormatterServices.GetSafeUninitializedObject(subTypes[selectIndex]);
158
- // curIndex = selectIndex;
159
- // property.serializedObject.ApplyModifiedProperties(); //更改多态类型后必须马上保存,否则后续序列化可能会出现异常
160
- //}
130
+ /// <summary>
131
+ /// 尝试使用无参构造函数创造实例,若失败则返回未初始化类型
132
+ /// </summary>
133
+ private object CreateInstance ( Type type ) {
134
+ foreach ( var constructor in type . GetConstructors ( ) ) {
135
+ if ( constructor . GetParameters ( ) . Length == 0 ) {
136
+ return constructor . Invoke ( null ) ;
137
+ }
138
+ }
139
+ return FormatterServices . GetSafeUninitializedObject ( type ) ;
161
140
}
141
+
142
+ //private Type GetRuntimeType(SerializedProperty property) {
143
+ // Type fieldType = fieldInfo.FieldType;
144
+ // bool canSerializeType = typeof(UnityEngine.Object).IsAssignableFrom(fieldType) || fieldType.IsValueType;
145
+ // if (canSerializeType || property.propertyType != SerializedPropertyType.ManagedReference) {
146
+ // return fieldInfo.FieldType;
147
+ // }
148
+ // else {
149
+ // string[] info = property.managedReferenceFieldTypename.Split();
150
+ // string asseblyName = info[0], typeName = info[1];
151
+ // Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(item => item.GetName().Name == asseblyName);
152
+ // return assembly.GetType(typeName);
153
+ // }
154
+ //}
155
+
162
156
#endregion
163
157
164
158
private object GetFieldOwner ( SerializedProperty property ) {
0 commit comments