1
+ #if ! NO_UNITY
2
+ using System ;
3
+ using System . Collections . Generic ;
4
+ using System . IO ;
5
+ using System . Linq ;
6
+ using System . Reflection ;
7
+ using FullSerializer . Internal ;
8
+ using UnityEditor ;
9
+ using UnityEngine ;
10
+
11
+ namespace FullSerializer {
12
+ [ InitializeOnLoad ]
13
+ public static class PlayStateNotifier {
14
+ static PlayStateNotifier ( ) {
15
+ EditorApplication . playmodeStateChanged += ModeChanged ;
16
+ }
17
+
18
+ private static void ModeChanged ( ) {
19
+ if ( ! EditorApplication . isPlayingOrWillChangePlaymode && EditorApplication . isPlaying ) {
20
+ Debug . Log ( "There are " + fsAotCompilationManager . AotCandidateTypes . Count + " candidate types" ) ;
21
+ foreach ( fsAotConfiguration target in Resources . FindObjectsOfTypeAll < fsAotConfiguration > ( ) ) {
22
+ var seen = new HashSet < string > ( target . aotTypes . Select ( t => t . FullTypeName ) ) ;
23
+ foreach ( Type type in fsAotCompilationManager . AotCandidateTypes ) {
24
+ if ( seen . Contains ( type . FullName ) == false ) {
25
+ target . aotTypes . Add ( new fsAotConfiguration . Entry ( type ) ) ;
26
+ EditorUtility . SetDirty ( target ) ;
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+
34
+ [ CustomEditor ( typeof ( fsAotConfiguration ) ) ]
35
+ public class fsAotConfigurationEditor : Editor {
36
+ [ NonSerialized ]
37
+ private List < Type > _allAotTypes ;
38
+ private List < Type > allAotTypes {
39
+ get {
40
+ if ( _allAotTypes == null )
41
+ _allAotTypes = FindAllAotTypes ( ) . ToList ( ) ;
42
+ return _allAotTypes ;
43
+ }
44
+ }
45
+
46
+ private string [ ] options = new string [ ] { "On" , "Off" , "[?]" } ;
47
+ private int GetIndexForState ( fsAotConfiguration . AotState state ) {
48
+ switch ( state ) {
49
+ case fsAotConfiguration . AotState . Enabled :
50
+ return 0 ;
51
+ case fsAotConfiguration . AotState . Disabled :
52
+ return 1 ;
53
+ case fsAotConfiguration . AotState . Default :
54
+ return 2 ;
55
+ }
56
+
57
+ throw new ArgumentException ( "state is invalid " + state ) ;
58
+ }
59
+ private fsAotConfiguration . AotState GetStateForIndex ( int index ) {
60
+ switch ( index ) {
61
+ case 0 : return fsAotConfiguration . AotState . Enabled ;
62
+ case 1 : return fsAotConfiguration . AotState . Disabled ;
63
+ case 2 : return fsAotConfiguration . AotState . Default ;
64
+ }
65
+
66
+ throw new ArgumentException ( "invalid index " + index ) ;
67
+ }
68
+
69
+ private IEnumerable < Type > FindAllAotTypes ( ) {
70
+ foreach ( var assembly in AppDomain . CurrentDomain . GetAssemblies ( ) ) {
71
+ foreach ( Type t in assembly . GetTypes ( ) ) {
72
+ bool performAot = false ;
73
+
74
+ // check for [fsObject]
75
+ {
76
+ var props = t . GetCustomAttributes ( typeof ( fsObjectAttribute ) , true ) ;
77
+ if ( props != null && props . Length > 0 ) performAot = true ;
78
+ }
79
+
80
+ // check for [fsProperty]
81
+ if ( ! performAot ) {
82
+ foreach ( PropertyInfo p in t . GetProperties ( ) ) {
83
+ var props = p . GetCustomAttributes ( typeof ( fsPropertyAttribute ) , true ) ;
84
+ if ( props . Length > 0 ) {
85
+ performAot = true ;
86
+ break ;
87
+ }
88
+ }
89
+ }
90
+
91
+ if ( performAot )
92
+ yield return t ;
93
+ }
94
+ }
95
+ }
96
+
97
+ private enum OutOfDateResult {
98
+ NoAot ,
99
+ Stale ,
100
+ Current
101
+ }
102
+ private OutOfDateResult IsOutOfDate ( Type type ) {
103
+ string converterName = fsAotCompilationManager . GetQualifiedConverterNameForType ( type ) ;
104
+ Type converterType = fsTypeCache . GetType ( converterName ) ;
105
+ if ( converterType == null )
106
+ return OutOfDateResult . NoAot ;
107
+
108
+ // TODO: We should also verify that the type is contained inside of fsConverterRegistrar as
109
+ // an additional diagnostic. If it is not, then that means the type will not be used
110
+ // at runtime.
111
+
112
+ object instance_ = null ;
113
+ try {
114
+ instance_ = Activator . CreateInstance ( converterType ) ;
115
+ } catch ( Exception ) { }
116
+ if ( instance_ is fsIAotConverter == false )
117
+ return OutOfDateResult . NoAot ;
118
+ var instance = ( fsIAotConverter ) instance_ ;
119
+
120
+ var metatype = fsMetaType . Get ( new fsConfig ( ) , type ) ;
121
+ if ( fsAotCompilationManager . IsAotModelUpToDate ( metatype , instance ) == false )
122
+ return OutOfDateResult . Stale ;
123
+
124
+ return OutOfDateResult . Current ;
125
+ }
126
+
127
+ private void DrawType ( fsAotConfiguration . Entry entry , Type resolvedType ) {
128
+ var target = ( fsAotConfiguration ) this . target ;
129
+
130
+ EditorGUILayout . BeginHorizontal ( ) ;
131
+
132
+ int currentIndex = GetIndexForState ( entry . State ) ;
133
+ int newIndex = GUILayout . Toolbar ( currentIndex , options , GUILayout . ExpandWidth ( false ) ) ;
134
+ if ( currentIndex != newIndex ) {
135
+ entry . State = GetStateForIndex ( newIndex ) ;
136
+ target . UpdateOrAddEntry ( entry ) ;
137
+ EditorUtility . SetDirty ( target ) ;
138
+ }
139
+
140
+ string displayName = entry . FullTypeName ;
141
+ string tooltip = "" ;
142
+ if ( resolvedType != null ) {
143
+ displayName = resolvedType . CSharpName ( ) ;
144
+ tooltip = resolvedType . CSharpName ( true ) ;
145
+ }
146
+ GUIContent label = new GUIContent ( displayName , tooltip ) ;
147
+ GUILayout . Label ( label ) ;
148
+
149
+ GUILayout . FlexibleSpace ( ) ;
150
+
151
+ GUIStyle messageStyle = new GUIStyle ( EditorStyles . label ) ;
152
+ string message ;
153
+ if ( resolvedType != null ) {
154
+ message = GetAotCompilationMessage ( resolvedType ) ;
155
+ if ( string . IsNullOrEmpty ( message ) == false ) {
156
+ messageStyle . normal . textColor = Color . red ;
157
+ } else {
158
+ switch ( IsOutOfDate ( resolvedType ) ) {
159
+ case OutOfDateResult . NoAot :
160
+ message = "No AOT model found" ;
161
+ break ;
162
+ case OutOfDateResult . Stale :
163
+ message = "Stale" ;
164
+ break ;
165
+ case OutOfDateResult . Current :
166
+ message = "\u2713 " ;
167
+ break ;
168
+ }
169
+ }
170
+ } else {
171
+ message = "Cannot load type" ;
172
+ }
173
+
174
+ GUILayout . Label ( message , messageStyle ) ;
175
+
176
+ EditorGUILayout . EndHorizontal ( ) ;
177
+ }
178
+
179
+ private string GetAotCompilationMessage ( Type type ) {
180
+ try {
181
+ fsMetaType . Get ( new fsConfig ( ) , type ) . EmitAotData ( true ) ;
182
+ } catch ( Exception e ) {
183
+ return e . Message ;
184
+ }
185
+ return "" ;
186
+ }
187
+
188
+ private Vector2 _scrollPos ;
189
+ public override void OnInspectorGUI ( ) {
190
+ var target = ( fsAotConfiguration ) this . target ;
191
+
192
+ if ( GUILayout . Button ( "Compile" ) ) {
193
+ if ( Directory . Exists ( target . outputDirectory ) == false )
194
+ Directory . CreateDirectory ( target . outputDirectory ) ;
195
+
196
+ foreach ( fsAotConfiguration . Entry entry in target . aotTypes ) {
197
+ if ( entry . State == fsAotConfiguration . AotState . Enabled ) {
198
+ Type resolvedType = fsTypeCache . GetType ( entry . FullTypeName ) ;
199
+ if ( resolvedType == null ) {
200
+ Debug . LogError ( "Cannot find type " + entry . FullTypeName ) ;
201
+ continue ;
202
+ }
203
+
204
+ try {
205
+ string compilation = fsAotCompilationManager . RunAotCompilationForType ( new fsConfig ( ) , resolvedType ) ;
206
+ string path = Path . Combine ( target . outputDirectory , "AotConverter_" + resolvedType . CSharpName ( true , true ) + ".cs" ) ;
207
+ File . WriteAllText ( path , compilation ) ;
208
+ } catch ( Exception e ) {
209
+ Debug . LogWarning ( "AOT compiling " + resolvedType . CSharpName ( true ) + " failed: " + e . Message ) ;
210
+ }
211
+ }
212
+ }
213
+ AssetDatabase . Refresh ( ) ;
214
+ }
215
+
216
+ target . outputDirectory = EditorGUILayout . TextField ( "Output Directory" , target . outputDirectory ) ;
217
+
218
+ EditorGUILayout . BeginHorizontal ( ) ;
219
+ GUILayout . Label ( "Set All" ) ;
220
+ int newIndex = GUILayout . Toolbar ( - 1 , options , GUILayout . ExpandWidth ( false ) ) ;
221
+ GUILayout . FlexibleSpace ( ) ;
222
+ EditorGUILayout . EndHorizontal ( ) ;
223
+ if ( newIndex != - 1 ) {
224
+ var newState = fsAotConfiguration . AotState . Default ;
225
+ if ( newIndex == 0 )
226
+ newState = fsAotConfiguration . AotState . Enabled ;
227
+ else if ( newIndex == 1 )
228
+ newState = fsAotConfiguration . AotState . Disabled ;
229
+
230
+ for ( int i = 0 ; i < target . aotTypes . Count ; ++ i ) {
231
+ var entry = target . aotTypes [ i ] ;
232
+ entry . State = newState ;
233
+ target . aotTypes [ i ] = entry ;
234
+ }
235
+ }
236
+
237
+
238
+ _scrollPos = EditorGUILayout . BeginScrollView ( _scrollPos ) ;
239
+ foreach ( fsAotConfiguration . Entry entry in target . aotTypes ) {
240
+ Type resolvedType = fsTypeCache . GetType ( entry . FullTypeName ) ;
241
+ EditorGUI . BeginDisabledGroup ( resolvedType == null || string . IsNullOrEmpty ( GetAotCompilationMessage ( resolvedType ) ) == false ) ;
242
+ DrawType ( entry , resolvedType ) ;
243
+ EditorGUI . EndDisabledGroup ( ) ;
244
+ }
245
+ EditorGUILayout . EndScrollView ( ) ;
246
+ }
247
+
248
+ }
249
+ }
250
+ #endif
0 commit comments